测试驱动开发 c#_在C#中通过测试驱动的开发获得一些动手实践

测试驱动开发 c#

by Moshe Binieli

由Moshe Binieli

在C#中通过测试驱动的开发获得一些动手实践 (Get some hands-on practice with test-driven development in C#)

因此,让我们谈谈TDD-这是什么? (So let’s talk about TDD — what is it?)

TDD stands for Test Driven Development, and it’s a design process in software development. It relies on the repetition of a very short development cycle, and the requirements are turned into very specific test cases.

TDD代表测试驱动开发 ,它是软件开发中的设计过程。 它依赖于非常短的开发周期的重复,并且需求变成了非常具体的测试用例。

There are a couple of steps in the TDD process:

TDD流程有几个步骤:

  1. Write a unit test that fails.

    编写失败的单元测试。
  2. Write enough code to make the test pass — at this step we don’t care about good code.

    编写足够的代码以使测试通过-在这一步,我们不在乎优质的代码。
  3. Refactor your code from the previous step.

    重构上一步中的代码。

这种方法有什么好处? (What are the benefits of this approach?)

First of all, you get a better understanding of the actual code before you write it. This is one of the greatest benefits of TDD. When you write the test cases first, you think more clearly about the system requirements and more critically about the corner cases.

首先,在编写代码之前您将对实际代码有更好的了解。 这是TDD的最大好处之一。 当您首先编写测试用例时,您会更清楚地思考系统需求,并更严格地考虑边缘案例

Also, when talking about dependencies, it’s important to mention that working with TDD lets you focus on the logic of your classes. This way you keep all the dependencies outside of your classes. It’s also important to mention that your code will run more safely since the logic will not have to handle difference dependencies such as database connections, file systems, and so on.

另外,在谈论依赖时 ,重要的是要提到使用TDD可以使您专注于类的逻辑。 这样,您可以将所有依赖项保留在类之外。 还必须提及的是,由于逻辑不必处理差异依赖性(例如数据库连接,文件系统等),因此代码将更安全地运行。

It’s also a safer way to refactor the code. When writing TDD there are tests for a certain piece of logic. When you refactor the code you might break something, but with this approach you know the tests will have your back.

这也是重构代码的一种更安全的方法。 在编写TDD时,需要对某些逻辑进行测试。 当您重构代码时,您可能会破坏某些东西,但是通过这种方法,您知道测试将得到支持。

When you use TDD, you also have a faster way to understand what the code does. When you start working on a piece of code that you are unfamiliar with, you can read the test cases of that piece of code and understand its purpose. Those tests are also the documentation for your code.

使用TDD时,您还可以更快地了解代码的作用。 当您开始处理自己不熟悉的代码时,您可以阅读该代码的测试用例并了解其用途。 这些测试也是您的代码的文档

And finally, you can focus on building the smaller components in the best way and avoid the headache of the big picture. So how does this help? You’ll write one failing test, and focus solely on that to get it passing. It forces you to think about smaller chunks of functionality at a time rather than the application as a whole. Then you can incrementally build on a passing test, rather than trying to tackle the bigger picture from the get-go, which will probably result in more bugs.

最后,您可以专注于以最佳方式构建较小的组件,从而避免大局的麻烦。 那么这有什么帮助呢? 您将编写一个失败的测试,并专注于该测试以使其通过。 它迫使您一次只考虑较小的功能块,而不是整个应用程序。 然后,您可以在通过测试的基础上逐步进行构建,而不是尝试从一开始就解决更大的问题,这可能会导致更多错误。

在我们开始编写TDD之前... (Before we start to write TDD…)

To be honest, there are more articles in which you can read even more deeply on TDD. Therefore, I avoided writing the whole theory of TDD here because it would take a very long time to read everything.

老实说,您可以在TDD上阅读更多文章。 因此,我避免在这里写整个TDD理论,因为阅读所有内容都需要很长时间。

Therefore I just explained the general idea and the advantages of the TDD design process.

因此,我只是解释了TDD设计过程的总体思想和优点。

是时候编写一些测试了,让我们开始吧 (It’s time to write some tests, so let’s do it)

说明和要求 (Description and requirements)

We will use C# to write a Stack implementation. Why C#? Well, because I love C#, so why not? ?

我们将使用C#编写Stack实现。 为什么要使用C#? 好吧,因为我爱C#,所以为什么不呢? ?

So our requirements are pretty simple: we want to implement a Stack class, so the requirements are:

因此,我们的要求非常简单:我们要实现Stack类,因此要求如下:

  1. Limit the size of the stack.

    限制堆栈的大小。
  2. Add element. (push)

    添加元素。 (推)
  3. Remove element. (pop)

    删除元素。 (流行音乐)
  4. Check what was the last element. (peek)

    检查什么是最后一个元素。 (窥视)
  5. Get the current size of the stack.

    获取当前堆栈的大小。
  6. Have a class that can accept any data type.

    有一个可以接受任何数据类型的类。
  7. When the customer exceeds the size of the Stack, we need to throw an appropriate exception.

    当客户超过堆栈的大小时,我们需要抛出适当的异常。

After we know what the requirements of the system are, we can start to define how we will solve this. We’ll implement it using an array.

在了解了系统的要求之后,我们可以开始定义如何解决此问题。 我们将使用数组来实现它。

TDD中的堆栈实现—建筑基础设施 (Stack implementation in TDD — Building infrastructure)

I use visual studio 2017. In it, I’ll open a new project:File -> New -> Project, Choose Console App (.NET Framework).Choose a project name — like “Stack”.

我使用Visual Studio2017。在其中,我将打开一个新项目: 文件->新建->项目,选择Conso le App(.NET Framework)。选择一个项目名称,例如“ Stack”。

Now we will open another project for the tests only and we will call it “StackTests”.

现在,我们将打开另一个仅用于测试的项目,我们将其称为“ StackTests”。

Open the solution explorer. We have one project over there called “Stack”. Now right click on Solution and choose Add -> New Project and choose Class Library (.NET Framework).

打开解决方案资源管理器。 我们在那里有一个名为“堆栈”的项目。 现在,右键单击解决方案,然后选择添加->新项目并选择类库 (.NET Framework)。

Let’s install our unit tests: right-click on the StackTests project, choose Manage NuGet Packages, navigate to “Browse” and install the following packages:

让我们安装单元测试:右键单击StackTests项目,选择Manage NuGet Packages ,导航到“ Browse”并安装以下软件包:

  • NUnit

    NUnit
  • NUnit3TestAdapter

    NUnit3TestAdapter

Add a new class to the StackTests project and call it StackTest. Now the solution should look like this:

StackTests项目添加一个新类,并将其命名为StackTest。 现在,解决方案应如下所示:

The packages.config should look like this:

packages.config应该如下所示:

TDD中的堆栈实现—编写代码 (Stack implementation in TDD — Write code)

We will start writing out test units in the StackTests project under StackTest class.

我们将开始在StackTest类的StackTests项目中写出测试单元。

Before we can start writing the code we need to learn 3 important things: TestFixture, Test, and Assert.

在开始编写代码之前,我们需要学习3个重要的知识: TestFixture,Test和Assert。

TestFixture is the attribute that marks a class that contains tests and, optionally, setup or teardown methods.

TestFixture是标记一个类的属性,该类包含测试以及(可选) 设置拆卸方法。

The Test attribute is one way of marking a method inside a TestFixture class as a test.

Test属性是将TestFixture类中的方法标记为测试的一种方法。

The Assert class is a collection of helper classes to test various conditions within unit tests. If the condition being tested is not met, an exception is thrown.

Assert类是用于在单元测试中测试各种条件的助手类的集合。 如果不满足所测试的条件,则会引发异常。

Import “NUnit.Framework” and put the [TestFixture] attribute above your class definition.

导入“ NUnit.Framework” ,并将[TestFixture]属性放在类定义上方。

创作测试 (Creation test)

Okay, it’s time to write our first function. We will write a creation test, which will create a new object of our Stack, and it will check that the size of the Stack is 0 at the beginning.

好的,是时候编写我们的第一个函数了。 我们将编写一个创建测试,它将创建我们的Stack的新对象,并将在开始时检查Stack的大小是否为0。

Now we’ve written our first test, so let’s run it.

现在我们编写了第一个测试,让我们运行它。

In your toolbar click Test -> Run -> All Tests.

在工具栏中,单击测试->运行->所有测试。

If your Test Explorer is not opened, click Test -> Windows -> Test Explorer, and this will expand the test explorer.

如果未打开“ 测试资源管理器” ,请单击“ 测试”->“ Windows”->“测试专家” ,这将展开测试资源管理器。

As you can see, we don’t even have our Stack class defined, so we’re getting a compilation error. Now let’s write enough code to make the test pass.

如您所见,我们甚至都没有定义Stack类,因此我们遇到了编译错误。 现在,让我们编写足够的代码以使测试通过。

Let’s make our first test work:

让我们进行第一个测试工作:

  • Create a new class in Stack project, and call this class “Stack”. Make this class a generic type class (T type).

    Stack项目中创建一个新类,并将其称为“ Stack”。 使此类成为泛型类型类(T类型)。

  • We defined this class (Stack) to be implemented as an array, therefore we will define the member field as an array of type T.

    我们将此类(Stack)定义为数组,因此将成员字段定义为T类型数组

  • We require to pass the maximum length of the stack at the constructor, therefore we will create a constructor that takes a size argument.

    我们需要在构造函数处传递堆栈的最大长度 ,因此我们将创建一个带有size参数的构造函数。

  • And since we require that we receive the current size of the stack at any point, we’ll define a property of “Size”. Of course, none will be able to change the size, therefore it will be a private set.

    而且由于我们要求在任何时候都接收堆栈的当前大小,因此我们将定义“ Size”属性 当然,任何人都无法更改大小,因此它将是私有集合

Now let’s run the tests again (check above how to run tests) and see the results.

现在,让我们再次运行测试(检查上面的运行方式)并查看结果。

And there we go, we’ve done our first iteration with TTD design! Now we should refactor our code — but at this point, we don’t really have anything to refactor, so we will move forward.

至此,我们已经完成了TTD设计的第一个迭代! 现在我们应该重构我们的代码-但是在这一点上,我们实际上没有任何要重构的东西,因此我们将继续前进。

推拉测试 (Push & Pop test)

Now we want to test push and pop functionality, so let’s create the test case.

现在我们要测试推送和弹出功能,因此让我们创建测试用例。

  • Push will take an argument and add it to the top of the stack.

    Push将接受一个参数并将其添加到堆栈的顶部。
  • Pop will remove the element from the stack and return it.

    Pop将从堆栈中删除该元素并将其返回。

We’ll add 3 elements to the stack, then we will take the last element out. At this point we will check that the last element is the exact one we expect to get and that the stack size decreased.

我们将3个元素添加到堆栈中,然后将最后一个元素取出。 在这一点上,我们将检查最后一个元素是否正是我们期望获得的元素,并且堆栈大小已减小。

As you can see, push and pop functions do not even exist, so when we run tests we get a failure in our test results. Let’s go to Stack class and implement them.

如您所见,push和pop函数甚至不存在,因此当我们运行测试时,我们的测试失败了。 检测结果。 让我们进入Stack类并实现它们。

Let’s run our tests again, and boom, everything works perfectly! All the tests passed successfully ?

让我们再次运行测试,繁荣,一切正常! 所有测试成功通过了吗?

错误超出允许的大小 (Error exceeding the allowed size)

We want to throw custom exceptions when we:

我们希望在以下情况下抛出自定义异常:

  1. Push new element when the stack is full.

    当堆栈已满时推入新元素。
  2. Pop element when there are no elements in the stack.

    当堆栈中没有元素时弹出元素。

So as you already know…what should we be doing now?

如您所知,我们现在应该做什么?

Correct! We define test cases, and then we make the code work.

正确! 我们定义测试用例,然后使代码工作。

As you can see, we need to create two new custom exceptions.

如您所见,我们需要创建两个新的自定义异常。

  • ExpenditureProhibitedException — This exception will occur when the stack is empty and the client attempts to pop a new element out.

    ExpenditureProhibitedException-当堆栈为空并且客户端尝试弹出新元素时,将发生此异常。

  • ExceededSizeException — This exception will occur when the stack is full and the client attempts to add a new element to the stack.

    ExceededSizeException-当堆栈已满并且客户端尝试向堆栈中添加新元素时,将发生此异常。

Go to Stack Project and create a new class called CustomExceptions. In this class we will define our new exceptions and they will inherit from the Exception class.

转到Stack Project并创建一个名为CustomExceptions的新类 在此类中,我们将定义新的异常,它们将从Exception类继承。

Modify our current push and pop functionality to throw an exception when needed.

修改我们当前的推送和弹出功能,以在需要时引发异常。

So now, as part of the TDD lifecycle, we’re running the tests… and Hooray! All tests have passed successfully.

因此,现在,作为TDD生命周期的一部分,我们正在运行测试……还有,万岁! 所有测试均已成功通过。

窥视最后一个元素 (Peek the last element)

We’re about to finish with the last tests. We want to peek the last element in the stack. If the stack is empty, we will throw an ExpenditureProhibitedException exception, otherwise, we will return the last element.

我们即将完成最后的测试。 我们想窥视堆栈中的最后一个元素。 如果堆栈为空,则将抛出ExpenditureProhibitedException异常,否则,将返回最后一个元素。

Let’s create our test cases.

让我们创建测试用例。

  1. Attempt to peek the element when the stack is empty. In this test we will throw a custom exception.

    堆栈为空时尝试窥视该元素。 在此测试中,我们将引发一个自定义异常。
  2. Insert some elements in the stack, then peek an element, make sure this is the correct element, and check that the array size hasn’t changed.

    在堆栈中插入一些元素,然后窥视一个元素,确保这是正确的元素,并检查数组大小是否未更改。

When we run the tests, they will fail — the peek method doesn’t even exist and there is no functionality.

当我们运行测试时,它们将失败—偷看方法甚至不存在,并且没有功能。

We’ll create the function Peek at Stack class.

我们将在Stack类中 创建函数Peek

Now when we run the tests again, we can see that all of them pass successfully.

现在,当我们再次运行测试时,我们可以看到所有测试均成功通过。

结论 (In conclusion)

As you can see, the idea is not complicated and there are many tools that help implement the TDD principles.

如您所见,这个想法并不复杂,并且有许多工具可以帮助实现TDD原则。

You can view the whole code at Pastebin.

您可以在Pastebin中查看整个代码。

Stack class — This class contains all the implementations of stack.StackTests class — Contains all the test cases.CustomExceptions classes — Contains the exceptions the system required for TDD design.

堆栈类-此类包含堆栈的所有实现。 StackTests类-包含所有测试用例。 CustomExceptions类-包含TDD设计所需的系统异常。

Every comment and all feedback is welcome — if it’s necessary, I will fix the article.

欢迎提出任何意见和所有反馈-如有必要,我将修复本文。

Feel free to contact me directly at LinkedIn — Click Here.

欢迎直接通过LinkedIn与我联系— 单击此处

翻译自: https://www.freecodecamp.org/news/tdd-explanation-hands-on-practice-with-c-a0124338be44/

测试驱动开发 c#

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值