TDD:为什么、如何以及现实世界的测试驱动代码

发布于 2024-12-09 13:45:23 字数 1035 浏览 0 评论 0原文

首先,请耐心解答我的所有问题。我以前从未使用过 TDD,但我越来越意识到我应该这样做。我已经阅读了很多关于 TDD 的文章以及如何指南,但有些事情仍然不清楚。用于演示的大多数示例要么是数学计算,要么是一些其他简单的运算。我还开始阅读 Roy Osherove 关于 TDD 的书。我有一些问题:

如果您的解决方案中有一个对象,例如一个 Account 类,那么测试在其上设置属性(例如帐户名称)有什么好处,那么您断言您设置的任何内容都是正确的。这会失败吗?

另一个例子,一个帐户余额,您创建一个余额为 300 的对象,然后断言余额实际上是 300。这怎么会失败呢?我在这里要测试什么?我可以看到使用不同的输入参数测试减法运算将是一个更好的测试。

我应该实际测试我的对象的什么目的?方法或属性?有时,您还会在基础设施层中将对象作为服务。就方法而言,如果您有一个三层应用程序,并且业务层正在调用数据层来获取某些数据。在这种情况下要测试什么?参数?数据对象不为空?那么服务方面呢?

然后是我关于现实生活项目的问题,如果你有一个绿色项目并且你想用 TDD 开始它。你首先从什么开始?你是把你的项目分成几个功能,然后对每个功能进行tdd,还是你实际上任意选择然后从那里开始。

例如,我有一个新项目,它需要登录功能。我是否从创建用户测试或帐户测试或登录测试开始?我先从哪一个开始?我在该课程中首先测试什么?

假设我决定创建一个具有用户名和密码以及其他一些属性的 User 类。我应该首先创建测试,修复所有构建错误,运行测试以使其失败,然后再次修复以获得绿灯,然后重构。那么我应该在该类上创建的第一个测试是什么?例如,是:

  • Username_Length_Greater_Than_6
  • Username_Length_Less_Than_12
  • Password_Complexity

如果您断言长度大于 6,那么如何测试代码?如果小于 6,我们是否会测试是否抛出错误?

如果我重复了我的问题,我很抱歉。我只是想开始使用 TDD,但我无法改变心态。谢谢你,希望有人能帮助我确定我在这里缺少什么。顺便问一下,有人知道我可以加入有关 TDD 的任何讨论组或聊天吗?

First, Please bear with me with all my questions. I have never used TDD before but more and more I come to realize that I should. I have read a lot of posts and how to guides on TDD but some things are still not clear. Most example used for demonstration are either math calculation or some other simple operations. I also started reading Roy Osherove's book about TDD. Here are some questions I have:

If you have an object in your solution, for instance an Account class, what is the benefit of testing setting a property on it, for example an account name, then you Assert that whatever you set is right. Would this ever fail?

Another example, an account balance, you create an object with balance 300 then you assert that the balance is actually 300. How would that ever fail? What would I be testing here? I can see testing a subtraction operation with different input parameters would be more of a good test.

What should I actually test my objects for? methods or properties? sometime you also have objects as service in an infrastructure layer. In the case of methods, if you have a three tier app and the business layer is calling the data layer for some data. What gets tested in that case? the parameters? the data object not being null? what about in the case of services?

Then on to my question regarding real life project, if you have a green project and you want to start it with TDD. What do you start with first? do you divide your project into features then tdd each one or do you actually pick arbitrarily and you go from there.

For example, I have a new project and it requires a login capability. Do I start with creating User tests or Account tests or Login tests. Which one I start with first? What do I test in that class first?

Let's say I decide to create a User class that has a username and password and some other properties. I'm supposed to create the test first, fix all build error, run the test for it to fail then fix again to get a green light then refactor. So what are the first tests I should create on that class? For example, is it:

  • Username_Length_Greater_Than_6
  • Username_Length_Less_Than_12
  • Password_Complexity

If you assert that length is greater than 6, how is that testing the code? do we test that we throw an error if it's less than 6?

I am sorry if I was repetitive with my questions. I'm just trying to get started with TDD and I have not been able to have a mindset change. Thank you and hopefully someone can help me determine what am I missing here. By the way, does anyone know of any discussion groups or chats regarding TDD that I can join?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

生生漫 2024-12-16 13:45:23

看一下低级 BDD。 Dan North 的这篇文章很好地介绍了它。

不要测试属性,而是考虑您正在寻找的行为。例如:

Account Behavior:
    should allow a user to choose the account name
    should allow funds to be added to the account

User Registration Behavior:
    should ensure that all usernames are between 6 and 12 characters
    should ask the password checker if the password is complex enough <-- you'd use a mock here

这些将成为每个类的测试,“应该”成为测试名称。每个测试都是如何有价值地使用该类的示例。您不是测试方法和属性,而是向其他人(或未来的您)展示为什么该类是有价值的以及如何安全地更改它。

我们还在 BDD 中做了一些称为“由外向内”的事情。因此,从 GUI 开始(或者通常是控制器/演示器,因为我们不经常对 GUI 进行单元测试)。

您已经知道 GUI 将如何使用控制器。现在写一个例子。您可能会有不止一方面的行为,因此请编写更多示例,直到控制器正常工作。控制器将有许多您尚未编写的协作类,因此请模拟它们 - 只需通过接口依赖注入它们即可。您可以稍后再写。

当您完成控制器后,用真实代码替换您在真实系统中模拟的下一个内容,并对其进行测试。哦,不要费心模拟域对象(比如帐户)——这会很麻烦——但是一定要向它们注入任何复杂的行为,然后模拟它。

这样,您总是可以为每个类编写您希望拥有的界面 - 易于使用的东西。您正在描述该类的行为并提供一些如何使用它的示例。您将使其安全且易于更改,并且适当的设计将会出现(随意遵循模式、深思熟虑的常识和经验)。

顺便说一句,对于登录,我倾向于弄清楚用户想要登录的目的,然后首先进行编码。稍后添加登录 - 通常风险不是很大,并且一旦编写就不会发生太大变化,因此您甚至可能不需要对其进行单元测试。由你决定。

Have a look at low-level BDD. This post by Dan North introduces it quite well.

Rather than testing properties, think about the behavior you're looking for. For instance:

Account Behavior:
    should allow a user to choose the account name
    should allow funds to be added to the account

User Registration Behavior:
    should ensure that all usernames are between 6 and 12 characters
    should ask the password checker if the password is complex enough <-- you'd use a mock here

These would then become tests for each class, with the "should" becoming the test name. Each test is an example of how the class can be used valuably. Instead of testing methods and properties, you're showing someone else (or your future self) why the class is valuable and how to change it safely.

We also do something in BDD called "outside-in". So start with the GUI (or normally the controller / presenter, since we don't often unit-test the GUI).

You already know how the GUI will use the controller. Now write an example of that. You'll probably have more than one aspect of behavior, so write more examples until the controller works. The controller will have a number of collaborating classes that you haven't written yet, so mock those out - just dependency inject them via an interface. You can write them later.

When you've finished with the controller, replace the next thing you've mocked out in the real system by real code, and test-drive that. Oh, and don't bother mocking out domain objects (like Account) - it'll be a pain in the neck - but do inject any complex behavior into them and mock that out instead.

This way, you're always writing the interface that you wish you had - something that's easy to use - for every class. You're describing the behavior of that class and providing some examples of how to use it. You're making it safe and easy to change, and the appropriate design will emerge (feel free to be guided by patterns, thoughtful common sense and experience).

BTW, with Login, I tend to work out what the user wants to log in for, then code that first. Add Login later - it's usually not very risky and doesn't change much once it's written, so you may not even need to unit-test it. Up to you.

  1. 测试直到恐惧被无聊取代。属性访问器和构造函数对于编写测试来说成本很高。我通常会间接测试它们,作为其他(更高)测试的一部分。

  2. 对于新项目,我建议查看 ATDD。找到您想要首先选择的用户故事(基于用户价值)。编写一个在用户故事完成后应该通过的验收测试。现在使用 TDD 深入了解 AT 通过所需的类型。验收测试将告诉您需要哪些对象和哪些行为。然后,您可以使用 TDD 一次实现一个。当您的所有测试(包括您的 acc. 测试)通过后,您将选择下一个用户故事并重复。

假设您选择“创建用户”作为您的第一个故事。然后你写一些例子来说明它应该如何工作。将它们转变为自动化验收测试。
创建有效用户->应该创建帐户
创建无效用户(显示无效内容的差异组合)->不应创建帐户,向用户显示有用的错误

AccountsVM.CreateUser(用户名,密码)
AccountsVM.HasUser(用户名)
AccountsVM.ErrorMessage

测试表明您需要上述内容。然后你去试驾他们。

  1. Test until fear is replaced by boredom. Property accessors and constructors are high cost to benefit to write tests against. I usually test them indirectly as part of some other (higher) test.

  2. For a new project, I'd recommend looking at ATDD. Find a user-story that you want to pick first (based on user value). Write an acceptance test that should pass when the user story is done. Now drill down into the types that you'd need to get the AT to pass -- using TDD. The acceptance test will tell you which objects and what behaviors are required. You then implement them one at a time using TDD. When all your tests (incl your acc. test) pass - you pick up the next user story and repeat.

Let's say you pick 'Create user' as your first story. Then you write examples of how that should work. Turn them into automated acceptance tests.
create valid user -> account should be created
create invalid user ( diff combinations that show what is invalid ) -> account shouldn't be created, helpful error shown to the user

AccountsVM.CreateUser(username, password)
AccountsVM.HasUser(username)
AccountsVM.ErrorMessage

The test would show that you need the above. You then go test-drive them them out.

复古式 2024-12-16 13:45:23

不要测试太简单而难以破解的东西。

  • getter 和 setter 太简单了,无法被破坏,所以说,代码太简单了,不会发生错误。

  • 您测试公共方法并断言响应符合预期。如果方法返回无效,您必须测试“附带后果”(有时并不容易,例如测试电子邮件已发送)。发生这种情况时,您可以使用模拟来测试方法的执行方式(而不是响应)(您询问模拟,被测类是否以所需的方式调用他)

我开始使用 Katas 来学习基础知识:JUnit 和 TestNG;然后是哈姆克雷斯特;然后阅读 EasyMock 或 Mockito 文档。

在 github 或这里寻找 katas
http://codekata.pragprog.com
http://codingdojo.org/

第一个测试应该是最简单的!也许只是迫使您创建 CUT(测试中的类)

但是,再次尝试 katas!

http://codingdojo.org/cgi-bin/wiki.pl?KataFizzBu​​zz

Don't test what is too simple to break.

  • getters and setters are too simple to be broken, so said, the code is so simple that an error can not happen.

  • you test the public methods and assert the response is as expected. If the method return void you have to test "collateral consequences" (sometimes is not easy, eg to test a email was sent). When this happens you can use mocks to test not the response but how the method executes (you ask the mockk if the Class Under Test called him the desired way)

I start doing Katas to learn the basics: JUnit and TestNG; then Harmcrest; then read EasyMock or Mockito documentation.

Look for katas at github, or here
http://codekata.pragprog.com
http://codingdojo.org/

The first test should be the easiest one! Maybe one that just force you to create the CUT (class under test)

But again, try katas!

http://codingdojo.org/cgi-bin/wiki.pl?KataFizzBuzz

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文