When you've come up with an overall design / idea for how a part of a system should work, how do you decide where to start when doing TDD, or rather, how do you decide your first test to start with?
当你想出一个系统的一部分应该如何工作的整体设计/想法时,你如何决定在做TDD时从哪里开始,或者更确切地说,你如何决定你的第一个测试开始?
5 个解决方案
#1
Lets assume I'm coding a class called Oven
to bake my delicious Pie
objects. This is how I step through the unit-test order:
让我们假设我正在编写一个名为Oven的类来烘焙我的美味Pie对象。这就是我逐步完成单元测试的顺序:
- What do I need to do to instantiate the object? In this case it would most likely be
Oven oven = new Oven();
No test for this one, I suppose. - How do I prepare the object for use?
oven.turnOn(int degrees)
sounds good, I'll do that. How do I check it? Better makeoven.getTemperature()
. There's an obvious test. - Okay, oven is now hot enough and I want to bake my
Pie
. For that I needoven.bake(Pie p)
so I'll make that. But now what? I want to check if the pie is ready but rather than havingoven.isPieReady()
I think thatoven.pastryStatus()
which returns things like "nothing in oven", "raw", "almost done", "cooked" and "charred" sounds good and in general should be more extendable thanoven.isPieReady()
so I'll do that.
我需要做什么来实例化对象?在这种情况下,它很可能是烤箱烤箱=新烤箱();我想,没有对这个测试。
如何准备使用对象? oven.turnOn(int degrees)听起来不错,我会这样做的。我该如何检查?最好制作oven.getTemperature()。有一个明显的考验。
好吧,烤箱现在已经足够热了,我想烤我的馅饼。为此,我需要烤箱。烘烤(饼干),所以我会做到这一点。但现在呢?我想检查馅饼是否准备好,而不是烤箱.isPieReady()我认为烤箱.pastryStatus()返回的东西,如“烤箱里没什么”,“生吃”,“差不多完成”,“煮熟”和“烧焦“听起来不错,一般来说应该比oven.isPieReady()更容易扩展,所以我会这样做。
And so on and so forth. So, I'll make my tests in order I expect to use the object refining the specification as I go. In the end I usually end up with rather simple yet powerful API which does what I want. After I've unit tested my API, I run coverage on my code to see what I missed and then add extra tests for those.
等等等等。所以,我将按照我希望使用对象来改进规范的方式进行测试。最后,我通常会得到相当简单但功能强大的API,它可以满足我的需求。在我对我的API进行单元测试之后,我对我的代码进行了覆盖,以查看我错过的内容,然后为这些内容添加额外的测试。
#2
When faced with a list of tests to implement, you'll have categories
当面对要实施的测试列表时,您将拥有类别
- Trivial to test but you're sure you can get this done.
- Non-trivial but you're reasonably confident of getting it done.
- Non-trivial but difficult-absolutely no clue of getting it done.
琐碎的测试,但你确定你可以做到这一点。
非平凡,但你有理由相信它完成它。
完成任务的非平凡但难以完全没有任何线索。
In such a scenario, Pick one from the Category2 bucket because it will provide with max knowledge/learning per unit of invested time. Plus it will get you rolling and boost confidence to ramp up to the more difficult Category3 tests.
在这种情况下,从Category2桶中选择一个,因为它将提供每单位投入时间的最大知识/学习。此外,它将让您滚动并增强信心,以适应更困难的Category3测试。
I think I got this from TDD By Example - Kent Beck. Have a look in case you have the time.. Recommended.
我想我从TDD中得到了这个例子 - Kent Beck。如果您有时间,请查看..推荐。
#3
I've been teaching an in-house class on TDD for a while now, and a lot of the participants start off by testing all the error cases. Relevant as they may be, that is not the best way to start imo.
我一直在TDD上教一个内部课程,很多参与者都是从测试所有错误案例开始的。虽然它们可能相关,但这不是启动imo的最佳方式。
Start by setting up tests, that are easy to implement and still tell you if you are moving in the right direction in regards to the features you're trying to implement. So if you're building a stack make sure that you verify push and pop before testing the error cases.
首先设置测试,这些测试易于实现,并且仍然告诉您是否正在朝着正在尝试实现的功能的方向前进。因此,如果您正在构建堆栈,请确保在测试错误情况之前验证推送和弹出。
Remember that the goal of the test is not only to verify behavior, but also to let you use the interface of the type under test. If writing the tests feels wrong, you probably need to change the interface.
请记住,测试的目标不仅是验证行为,还要让您使用被测类型的接口。如果编写测试感觉不对,您可能需要更改界面。
A good idea is to do each test case backwards. So start by writing the Assert statement. This is the goal of the verification for this test. Then add whatever steps are necessary to get to the point where you can do what the Assert does.
一个好主意是向后做每个测试用例。所以从编写Assert语句开始。这是此测试验证的目标。然后添加必要的步骤,以达到可以执行Assert所做的操作。
#4
I would build a set of units for the most independent/lowest-level functionality. Once you have those classes passing every test, you can move on, assuming they will work when called by more dependent functionality.
我会为最独立/最低级别的功能构建一组单元。一旦你让这些类通过了每个测试,你就可以继续前进,假设它们在被更多依赖功能调用时会工作。
#5
These are generic guidelines I find useful for prioritizing unit testing:
这些是我发现用于优先考虑单元测试的通用指南:
1) Identify Boundary Objects (Win/WebForms, CustomControls etc).
1)识别边界对象(Win / WebForms,CustomControls等)。
2) Identify Control Objects (Business layer objects)
2)识别控制对象(业务层对象)
3) Write Unit tests only for control objects public methods invoked by boundary objects. This way you'll be sure you're covering main functional aspects of your app.
3)Write Unit测试仅针对边界对象调用的控制对象公共方法。这样您就可以确定自己正在涵盖应用程序的主要功能方面。
You can use these rules to prioritize your unit testing - then if you need to micro-test other stuff you can also do it depending on your needs.
您可以使用这些规则来确定单元测试的优先级 - 然后,如果您需要对其他内容进行微测试,您也可以根据需要进行测试。
#1
Lets assume I'm coding a class called Oven
to bake my delicious Pie
objects. This is how I step through the unit-test order:
让我们假设我正在编写一个名为Oven的类来烘焙我的美味Pie对象。这就是我逐步完成单元测试的顺序:
- What do I need to do to instantiate the object? In this case it would most likely be
Oven oven = new Oven();
No test for this one, I suppose. - How do I prepare the object for use?
oven.turnOn(int degrees)
sounds good, I'll do that. How do I check it? Better makeoven.getTemperature()
. There's an obvious test. - Okay, oven is now hot enough and I want to bake my
Pie
. For that I needoven.bake(Pie p)
so I'll make that. But now what? I want to check if the pie is ready but rather than havingoven.isPieReady()
I think thatoven.pastryStatus()
which returns things like "nothing in oven", "raw", "almost done", "cooked" and "charred" sounds good and in general should be more extendable thanoven.isPieReady()
so I'll do that.
我需要做什么来实例化对象?在这种情况下,它很可能是烤箱烤箱=新烤箱();我想,没有对这个测试。
如何准备使用对象? oven.turnOn(int degrees)听起来不错,我会这样做的。我该如何检查?最好制作oven.getTemperature()。有一个明显的考验。
好吧,烤箱现在已经足够热了,我想烤我的馅饼。为此,我需要烤箱。烘烤(饼干),所以我会做到这一点。但现在呢?我想检查馅饼是否准备好,而不是烤箱.isPieReady()我认为烤箱.pastryStatus()返回的东西,如“烤箱里没什么”,“生吃”,“差不多完成”,“煮熟”和“烧焦“听起来不错,一般来说应该比oven.isPieReady()更容易扩展,所以我会这样做。
And so on and so forth. So, I'll make my tests in order I expect to use the object refining the specification as I go. In the end I usually end up with rather simple yet powerful API which does what I want. After I've unit tested my API, I run coverage on my code to see what I missed and then add extra tests for those.
等等等等。所以,我将按照我希望使用对象来改进规范的方式进行测试。最后,我通常会得到相当简单但功能强大的API,它可以满足我的需求。在我对我的API进行单元测试之后,我对我的代码进行了覆盖,以查看我错过的内容,然后为这些内容添加额外的测试。
#2
When faced with a list of tests to implement, you'll have categories
当面对要实施的测试列表时,您将拥有类别
- Trivial to test but you're sure you can get this done.
- Non-trivial but you're reasonably confident of getting it done.
- Non-trivial but difficult-absolutely no clue of getting it done.
琐碎的测试,但你确定你可以做到这一点。
非平凡,但你有理由相信它完成它。
完成任务的非平凡但难以完全没有任何线索。
In such a scenario, Pick one from the Category2 bucket because it will provide with max knowledge/learning per unit of invested time. Plus it will get you rolling and boost confidence to ramp up to the more difficult Category3 tests.
在这种情况下,从Category2桶中选择一个,因为它将提供每单位投入时间的最大知识/学习。此外,它将让您滚动并增强信心,以适应更困难的Category3测试。
I think I got this from TDD By Example - Kent Beck. Have a look in case you have the time.. Recommended.
我想我从TDD中得到了这个例子 - Kent Beck。如果您有时间,请查看..推荐。
#3
I've been teaching an in-house class on TDD for a while now, and a lot of the participants start off by testing all the error cases. Relevant as they may be, that is not the best way to start imo.
我一直在TDD上教一个内部课程,很多参与者都是从测试所有错误案例开始的。虽然它们可能相关,但这不是启动imo的最佳方式。
Start by setting up tests, that are easy to implement and still tell you if you are moving in the right direction in regards to the features you're trying to implement. So if you're building a stack make sure that you verify push and pop before testing the error cases.
首先设置测试,这些测试易于实现,并且仍然告诉您是否正在朝着正在尝试实现的功能的方向前进。因此,如果您正在构建堆栈,请确保在测试错误情况之前验证推送和弹出。
Remember that the goal of the test is not only to verify behavior, but also to let you use the interface of the type under test. If writing the tests feels wrong, you probably need to change the interface.
请记住,测试的目标不仅是验证行为,还要让您使用被测类型的接口。如果编写测试感觉不对,您可能需要更改界面。
A good idea is to do each test case backwards. So start by writing the Assert statement. This is the goal of the verification for this test. Then add whatever steps are necessary to get to the point where you can do what the Assert does.
一个好主意是向后做每个测试用例。所以从编写Assert语句开始。这是此测试验证的目标。然后添加必要的步骤,以达到可以执行Assert所做的操作。
#4
I would build a set of units for the most independent/lowest-level functionality. Once you have those classes passing every test, you can move on, assuming they will work when called by more dependent functionality.
我会为最独立/最低级别的功能构建一组单元。一旦你让这些类通过了每个测试,你就可以继续前进,假设它们在被更多依赖功能调用时会工作。
#5
These are generic guidelines I find useful for prioritizing unit testing:
这些是我发现用于优先考虑单元测试的通用指南:
1) Identify Boundary Objects (Win/WebForms, CustomControls etc).
1)识别边界对象(Win / WebForms,CustomControls等)。
2) Identify Control Objects (Business layer objects)
2)识别控制对象(业务层对象)
3) Write Unit tests only for control objects public methods invoked by boundary objects. This way you'll be sure you're covering main functional aspects of your app.
3)Write Unit测试仅针对边界对象调用的控制对象公共方法。这样您就可以确定自己正在涵盖应用程序的主要功能方面。
You can use these rules to prioritize your unit testing - then if you need to micro-test other stuff you can also do it depending on your needs.
您可以使用这些规则来确定单元测试的优先级 - 然后,如果您需要对其他内容进行微测试,您也可以根据需要进行测试。