在进行TDD时发现其他对象

时间:2021-02-04 18:03:00

I am trying to practice TDD.

我正在尝试练习TDD。

My understanding is that TDD should go like this

我的理解是TDD应该是这样的

  1. Write a test list for the interface/class I am going to develop.
  2. 为我要开发的接口/类写一个测试列表。

  3. Start with the easiest not implemented test from my test list.
  4. 从我的测试列表中最简单的未实现的测试开始。

  5. Write the test, no implementation code yet.
  6. 编写测试,还没有实现代码。

  7. Write the interface of the class to make the code compile.
  8. 编写类的接口以使代码编译。

  9. Run the test resulting in one failing test.
  10. 运行测试导致一个失败的测试。

  11. Write the implementation making the test pass.
  12. 编写实现测试通过。

  13. Refactor the mess I've made.
  14. 重构我所做的混乱。

  15. Goto 2.

The problem I have is when writing the implementation or doing the refactoring. I often come to the conclusion that the implementation I just wrote should be delegated to another class.

我遇到的问题是编写实现或进行重构时。我经常得出结论,我刚写的实现应该委托给另一个类。

What should a true TDD'r do at this point?

在这一点上真正的TDD应该怎么做?

  1. Leave the existing test list alone for a while and create a new one for the newly discovered class (the same problem can manifest itself when implementing the new class offcourse)
  2. 将现有的测试列表单独保留一段时间,并为新发现的类创建一个新的测试列表(在实现新的类别时,同样的问题可以表现出来)

  3. Go the Interaction Based way of testing and Mock the new class, continue with the testcases of the class you are working on and come back later to create a correct implementation of the mocked class.
  4. 转到基于交互的测试方法并模拟新类,继续使用您正在处理的类的测试用例,稍后再回来创建模拟类的正确实现。

  5. This situation should not present itself. I probably have not thought out my initial design well enough. (but wouldn't that defeat one of the purposes of TDD?!).
  6. 这种情况不应该出现。我可能还没有充分考虑我的初始设计。 (但这不会破坏TDD的目的之一吗?!)。

I'd love to know how other people handle these situations.

我很想知道其他人如何处理这些情况。

4 个解决方案

#1


Don't look for a one-to-one relationship between your tests and your classes. If you decide to introduce a new class, let that be a refactoring supported by the original test, and add tests in the appropriate place (where that is depends on the specific case) when you want to add functionality (or to test eventualities you need to cover that you didn't test for yet).

不要在测试和类之间寻找一对一的关系。如果您决定引入一个新类,那么让它成为原始测试支持的重构,并在您想要添加功能(或测试您需要的事件)时在适当的位置添加测试(这取决于具体情况)覆盖你尚未测试的东西)。

I would add that the main success in TDD is to get into the rhythm of red-green-refactor. When you feel the benefit of that rhythm, you have started to "get" it. That isn't to say you will find it worthwhile in all cases, but until you feel that rhythm you haven't gotten to what its advocates like about it.

我想补充一点,TDD的主要成功是进入红绿重构的节奏。当你感受到节奏的好处时,你已经开始“得到”它。这并不是说在所有情况下都会发现它值得,但在你感受到这种节奏之前,你还没有达到它的拥护者所喜欢的那样。

And there is usually (especially in architecturally complicated applications, like n-tier applications) some amount of up-front design. Nothing sketched in stone, but enough to give the units a place to go. Of course the architecture may evolve in an agile methodology, but a general idea of the landscape needs to be there if there are multiple layers to the architecture.

通常(特别是在架构复杂的应用程序中,如n层应用程序)有一些预先设计。什么都没有用石头勾勒出来,但足以让这些单位成为一个可以去的地方。当然,架构可能会以敏捷方法发展,但如果架构有多个层,则需要对场景进行总体思考。

EDIT: (In response to the comment). Should the new class get tested in its own right? Not necessarily. It depends if the class develops an importance of its own. When you are unit testing, you are testing a piece of functionality. It isn't an integration test just because there are two classes involved. It becomes an integration test when two units start interacting. The boundary I typically think of is if I have to set up significant state in group-of-classes A to interact with group-of-classes B, and especially if group-of-classes A calls group-of-classes B and what I am interested in testing is how B reacted to A, then I'm looking at an integration test.

编辑:(回应评论)。新课程是否应该自行测试?不必要。这取决于班级是否发展了自己的重要性。当您进行单元测试时,您正在测试一项功能。它不是一个集成测试,因为涉及两个类。当两个单元开始交互时,它就变成了集成测试。我通常想到的边界是,如果我必须在类组A中设置重要状态以与类组B交互,特别是如果类组A调用类组B和什么我感兴趣的是测试B是如何对A做出反应的,然后我正在研究集成测试。

#2


The problem I have is that when I arrive at point 6 & 7, at some point in time I invariably come to the conclusion that the implementation I just wrote should be delegated to another class.

我遇到的问题是,当我到达第6点和第7点时,在某个时间点,我总是得出结论,我刚写的实现应该委托给另一个类。

Realizing your design would be better with a different class - that's design, and that's the point of TDD. So it's a fine thing, and it shouldn't bother you.

通过不同的类来实现您的设计会更好 - 这就是设计,这就是TDD的重点。所以这是一件好事,它不应该打扰你。

But it's bothering you. So what to do? Recognize that delegating to another class is a refactoring; this is something to be done after step 6, during step 7. Once you're green, refactor to a better design. You've already got the tests for the new class; they're just wired to call the original class. That's perfectly fine. After extracting the class and delegating, if you would be more comfortable having the tests call the extracted class directly: go for it. No harm. If the extracted class starts to get used by other callers, I'd recommend it, and maybe when you start calling it from other classes is a good time to do that (but if it bugs you now, do it now).

但它困扰着你。那么该怎么办?认识到委托给另一个班级是重构;这是在步骤6之后,在步骤7中要做的事情。一旦你变绿了,重构一个更好的设计。你已经完成了新课程的测试;他们只是打电话给原来的班级。那很好。在提取类和委托之后,如果你更愿意让测试直接调用提取的类:去吧。无害。如果提取的类开始被其他调用者使用,我会推荐它,也许当你从其他类开始调用它时,这是一个很好的时间(但如果它现在有问题,现在就去做)。

#3


When I run into this situation, I follow your solution #1. Keep recursing, making as many classes as you feel are appropriate, until you have a collection of implementations you're happy with. With experience you'll find that your designs reflect your experience, and this sort of thing won't happen as much.

当我遇到这种情况时,我会按照您的解决方案#1。继续递归,根据您的需要制作尽可能多的课程,直到您拥有一系列令您满意的实施。根据经验,您会发现您的设计反映了您的体验,而且这种事情不会发生太多。

#4


You should create a mock class. A single interface with predictable retults. So you can test the original.

你应该创建一个模拟类。具有可预测的报告的单一界面。所以你可以测试原件。

Later on, you can repeat the procedure with the new class.

稍后,您可以使用新类重复该过程。

#1


Don't look for a one-to-one relationship between your tests and your classes. If you decide to introduce a new class, let that be a refactoring supported by the original test, and add tests in the appropriate place (where that is depends on the specific case) when you want to add functionality (or to test eventualities you need to cover that you didn't test for yet).

不要在测试和类之间寻找一对一的关系。如果您决定引入一个新类,那么让它成为原始测试支持的重构,并在您想要添加功能(或测试您需要的事件)时在适当的位置添加测试(这取决于具体情况)覆盖你尚未测试的东西)。

I would add that the main success in TDD is to get into the rhythm of red-green-refactor. When you feel the benefit of that rhythm, you have started to "get" it. That isn't to say you will find it worthwhile in all cases, but until you feel that rhythm you haven't gotten to what its advocates like about it.

我想补充一点,TDD的主要成功是进入红绿重构的节奏。当你感受到节奏的好处时,你已经开始“得到”它。这并不是说在所有情况下都会发现它值得,但在你感受到这种节奏之前,你还没有达到它的拥护者所喜欢的那样。

And there is usually (especially in architecturally complicated applications, like n-tier applications) some amount of up-front design. Nothing sketched in stone, but enough to give the units a place to go. Of course the architecture may evolve in an agile methodology, but a general idea of the landscape needs to be there if there are multiple layers to the architecture.

通常(特别是在架构复杂的应用程序中,如n层应用程序)有一些预先设计。什么都没有用石头勾勒出来,但足以让这些单位成为一个可以去的地方。当然,架构可能会以敏捷方法发展,但如果架构有多个层,则需要对场景进行总体思考。

EDIT: (In response to the comment). Should the new class get tested in its own right? Not necessarily. It depends if the class develops an importance of its own. When you are unit testing, you are testing a piece of functionality. It isn't an integration test just because there are two classes involved. It becomes an integration test when two units start interacting. The boundary I typically think of is if I have to set up significant state in group-of-classes A to interact with group-of-classes B, and especially if group-of-classes A calls group-of-classes B and what I am interested in testing is how B reacted to A, then I'm looking at an integration test.

编辑:(回应评论)。新课程是否应该自行测试?不必要。这取决于班级是否发展了自己的重要性。当您进行单元测试时,您正在测试一项功能。它不是一个集成测试,因为涉及两个类。当两个单元开始交互时,它就变成了集成测试。我通常想到的边界是,如果我必须在类组A中设置重要状态以与类组B交互,特别是如果类组A调用类组B和什么我感兴趣的是测试B是如何对A做出反应的,然后我正在研究集成测试。

#2


The problem I have is that when I arrive at point 6 & 7, at some point in time I invariably come to the conclusion that the implementation I just wrote should be delegated to another class.

我遇到的问题是,当我到达第6点和第7点时,在某个时间点,我总是得出结论,我刚写的实现应该委托给另一个类。

Realizing your design would be better with a different class - that's design, and that's the point of TDD. So it's a fine thing, and it shouldn't bother you.

通过不同的类来实现您的设计会更好 - 这就是设计,这就是TDD的重点。所以这是一件好事,它不应该打扰你。

But it's bothering you. So what to do? Recognize that delegating to another class is a refactoring; this is something to be done after step 6, during step 7. Once you're green, refactor to a better design. You've already got the tests for the new class; they're just wired to call the original class. That's perfectly fine. After extracting the class and delegating, if you would be more comfortable having the tests call the extracted class directly: go for it. No harm. If the extracted class starts to get used by other callers, I'd recommend it, and maybe when you start calling it from other classes is a good time to do that (but if it bugs you now, do it now).

但它困扰着你。那么该怎么办?认识到委托给另一个班级是重构;这是在步骤6之后,在步骤7中要做的事情。一旦你变绿了,重构一个更好的设计。你已经完成了新课程的测试;他们只是打电话给原来的班级。那很好。在提取类和委托之后,如果你更愿意让测试直接调用提取的类:去吧。无害。如果提取的类开始被其他调用者使用,我会推荐它,也许当你从其他类开始调用它时,这是一个很好的时间(但如果它现在有问题,现在就去做)。

#3


When I run into this situation, I follow your solution #1. Keep recursing, making as many classes as you feel are appropriate, until you have a collection of implementations you're happy with. With experience you'll find that your designs reflect your experience, and this sort of thing won't happen as much.

当我遇到这种情况时,我会按照您的解决方案#1。继续递归,根据您的需要制作尽可能多的课程,直到您拥有一系列令您满意的实施。根据经验,您会发现您的设计反映了您的体验,而且这种事情不会发生太多。

#4


You should create a mock class. A single interface with predictable retults. So you can test the original.

你应该创建一个模拟类。具有可预测的报告的单一界面。所以你可以测试原件。

Later on, you can repeat the procedure with the new class.

稍后,您可以使用新类重复该过程。