保持源代码的紧密性和单元测试的紧密性
当我第一次开始使用单元测试时,我遇到了两个问题。 首先是能够测试私有方法和字段,其次是在快速开发时落后于保持单元测试最新。 因此,我采用了以下方法进行单元测试。
#if UNITTEST
using NUnit.Framework;
#endif
public class MyBlackMagic
{
private int DoMagic()
{
return 1;
}
#if UNITTEST
[TestFixture]
public class MyBlackMagicUnitTest
{
[TestFixtureSetUp]
public void Init()
{
log4net.Config.BasicConfigurator.Configure();
}
[Test]
public void DoMagicTest()
{
Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name);
Assert.IsTrue(DoMagic() == 1, "You are not a real magician!");
}
}
#endif
}
我发现这种方法克服了我的两个问题,只需轻轻一按预编译器开关即可确保所有单元测试都能编译。
我现在的问题是,我正在转向一个新项目,其中讨论的是使用单独的程序集来进行单元测试。 在我深入探讨并开始阐述上面所示的内部类方法的优点之前,我想知道是否有人认为它有任何缺点?
编辑:
只是针对提到的一些弱点添加几点:
- 单元测试代码永远不会影响生产代码,因为 UNITTEST 预编译器标志被关闭,
- 单元测试代码不会使主代码变得更少可读,因为它位于每个类的底部并包装在 Visual Studio 区域指令中,
- 我发现内部单元测试类意味着主类实际上更简单,因为没有为了测试而必须公开的额外方法或属性。 总会有这样的情况,您迟早想要测试类的某些内部状态作为单元测试的一部分......
When I first started using unit tests I encountered two problems. First was being able to test private methods and fields and second falling behind on keeping unit tests up to date when rapid development was taking place. Consequently I adopted the approach below for my unit tests.
#if UNITTEST
using NUnit.Framework;
#endif
public class MyBlackMagic
{
private int DoMagic()
{
return 1;
}
#if UNITTEST
[TestFixture]
public class MyBlackMagicUnitTest
{
[TestFixtureSetUp]
public void Init()
{
log4net.Config.BasicConfigurator.Configure();
}
[Test]
public void DoMagicTest()
{
Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name);
Assert.IsTrue(DoMagic() == 1, "You are not a real magician!");
}
}
#endif
}
I find that approach overcomes my two problems and it's a flick of a pre-compiler switch to make sure all the unit tests compile.
My problem now is that I am moving to a new project where the talk is of using seperate assemblies to hold the unit tests. Before I dive in and start expounding on the virtues of the internal class approach as shown above I'd like to know if anyone thinks it has any shortcomings?
Edit:
Just to add a couple of points around some of the mentioned weaknesses:
- The unit testing code will never impact the production code since the UNITTEST pre-compiler flag gets switched off,
- The unit test code doesn't make the main code any less readable since it's placed at the bottom of each class and wrapped in a Visual Studio region directive,
- I find the internal unit test class means the main class is actually simpler as there are no extra methods or properties that have to be exposed just for testing. There will always be cases where you want to test some internal state of a class as part of a unit test sooner or later...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
我发现这种方法非常丑陋,因为它用测试方法混淆了你的真实逻辑,使你的源代码更难阅读。
除此之外,您还对项目本身中的 NUnit 程序集有依赖关系(引用)。 尽管在没有unit_test条件定义的情况下进行编译时,依赖关系不是必需的,但这非常丑陋且不必要。
如果您想跟上单元测试,我建议您先编写测试,然后再实现真正的代码。
编写单元测试不仅仅是测试; 它还与设计代码有关。
通过首先编写测试,您将开始考虑类的 API/接口,或者您希望如何使用这些类。
I find this approach very ugly, since it clutters your real logic with testing methods, making your source harder to read.
Next to that, you also have a dependency (reference) to the NUnit assemblies in your project itself. Although the dependency is not necessary when you compile without the unit_test conditional define, this is plain ugly and unneccessary.
If you want to keep up with your unit-tests, I advise you to write tests first, and then implement the real code.
Writing unit-tests is more then just about testing; it is also about designing code.
By writing the test first, you'll get to think of the API / the interface of your class, or how you want to use those classes.
您不应该单独测试私有方法,因为它们(应该!)从公共方法或可能的构造函数中使用 - 因此公共方法依赖于私有方法来成功完成其分配。
如果私有方法不执行其工作,这些公共方法/构造函数将(应该!)失败。 所以你的方法实际上是编写单元测试的糟糕方法。
并迭代以前的答案 - 在编写方法之前编写单元测试。
You shouldn't test private methods separately, because they are (should be!) used from public methods or possibly constructors - so the public methods depends on the private ones to succeed with their assignments.
These public methods/constructors will (should!) fail if the private methods don't do their work. So your approach is actually a bad approach for writing unit tests.
And to iterate the previous answers - write your unit tests before you write your methods.
如果您不能让所有测试始终成功(由于开发截止日期),那么我认为您没有非常认真地对待单元测试,并且在进行估计时应该考虑测试的维护。
If you can't keep all of the tests succeeding all of the time (because of development deadlines) then I think your not taking unit testing very serious and you should take the maintenance of the tests into account when making your estimates.
我发现将单元测试保留在自己的程序集中效果非常好,并且使用它时没有遇到任何问题。
但是,如果您发现自己需要测试某个类的私有成员,这可能意味着您的类正在做很多事情。 您最好将这些私有成员提取到一个新类中。 然后您可以通过其公共方法直接测试该新类。
I find that keeping my unit tests in their own assembly works very well, and haven't run into any problems using it.
However, if you find yourself needing to test private members of some class, that probably means your class is doing a lot of stuff. You may be better off extracting those private members into a new class. Then you can test that new class directly via its public methods.
请问,如何在将
UNITTEST
设置为 false 的任何构建上运行单元测试?我是一个蹩脚、懒惰的 TDD 实现者。 我没有编写足够多的测试,也没有太频繁地运行它们。 但即使我测试了我的发布版本。
And how, pray tell, do you run your unit tests on any build for which you've set
UNITTEST
to false?I'm a crappy, lazy implementer of TDD. I don't write anywhere near enough tests, and I don't run them way too infrequently. But even I test my release builds.
我认为这不是单元测试的设计目的。 如果您快速开发代码并且单元测试落后,那么它们当然会失败,但这不应该导致您使用黑魔法,而是编写单元测试。 如果您不喜欢这种方式,那么您根本不应该使用单元测试。
I think that's not what unit tests were designed for. If you have developed code quickly and your unit tests are behind, then they will fail of course, but this shouldn't lead you to use black magic, but to write the unit tests. If you don't like this way, then you shouldn't use unit tests at all.
将测试代码保留在其自己的单独程序集中的基本原理是因为测试代码不应该由用户“使用”。 单元测试仅用于验证代码是否执行指定的操作。 常见的做法是将测试代码放在它自己的程序集中,以便生产代码不依赖于测试代码和单元测试框架。
从这个代码示例中,我不清楚您要测试什么。 看起来您正在尝试测试一些并未完全与环境隔离的东西。 当 xUnit 测试运行程序可以为您记录测试结果时,为什么您还需要记录器?
内部类的测试很棘手,因为您需要内部类正在实现的公共接口(或抽象类),并且需要将其与创建它的类一起测试。 更明确的单元测试应该检查一个特定类的行为,如果以某种方式返回内部类,那么您需要检查它是否以正确的方式返回。
The rationale behind keeping test code in it's own seperate assembly is because test code is not supposed to be "used" by the user. Unit tests are only there to verify the code does what it is specified to do. The common practice is to put test code in it's own assembly so that the production code is not dependent on the test code and the unit test framework.
From this code example, it's not clear to me what you're trying to test. It seems like you're trying to test something that isn't in completely isolated from the environment. Why would you need a logger when xUnit test runners can log test results for you?
Internal classes are tricky to test because you need a public interface (or abstract class) that the internal class is implementing and you need to test that together with the class that created it. More explicitly unit tests should check the behavior of one specific class, and if an internal class is returned in a way, then you need to check it's returned in a correct manner.