在 Django 中,什么时候应该使用 doctests 而不是单元测试?
来自 Django 文档:
...数据库在文档测试之间不会刷新,因此如果您的文档测试需要某种状态,您应该考虑刷新数据库或加载固定装置。
坦率地说,我目前 90% 的测试都是在文档测试中完成的。我的一位同事认为这很奇怪。老实说,我很少做测试,所以我不会假装自己是该领域的大师。
在决定如何测试时,有人使用经验法则吗?
非 SO 答案
我的一位同事建议通过单元测试将模型功能和约束作为文档测试和视图进行测试。这听起来怎么样?
From Django docs:
...the database is not refreshed between doctests, so if your doctest requires a certain state you should consider flushing the database or loading a fixture.
Quite frankly, 90% of my testing is currently done in doctests. A colleague of mine thought that was peculiar. In all honesty, I do very little testing so I do not pretend to be a master of that field.
Does anyone have a rule of thumb they use when deciding how to test?
Non-SO answer
A colleague of mine suggested to test model functions and constraints as doctests and views via unit tests. How does that sound for a rule of thumb?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
随着项目的增长,您会发现单元测试更适合测试代码。
Django 项目本身正在将所有文档测试转换为单元测试(我们将在 1.3 版本中完成)。我们这样做的原因是,在此转换之前,测试套件中的执行顺序有时会导致难以重现的错误。有时,一些代码会意外地依赖于之前运行的文档测试代码。此外,切换到单元测试还加快了整体测试时间,因为我们可以更加明智地了解如何以及何时清除数据库。
单元测试的另一个优点是它们更容易维护。因为整个测试用例是独立的,所以您要么编写另一个测试用例,要么修改小的、有针对性的测试函数以适应。
文档测试倾向于通过进化来工作 - 你得到一个小部件的实例,添加绿色毛皮,确保毛皮是绿色的,添加 4 条腿,确保你有 4 条腿和绿色毛皮,添加一个拇指,确保你有一个拇指、4 条腿和绿色毛皮等...这意味着,如果您想在绿色毛皮阶段之后添加测试,则必须修改以下每个其他测试用例的预期结果。
您不想进行所有这些重写,因此您在最后添加了新测试。然后你添加另一个,然后过了一会儿你的测试就变得非常混乱,你甚至无法弄清楚是否测试了某个特定功能!使用单元测试,由于每个测试都体现了一个特定的、具体的和有限的想法,因此更容易逻辑地重新排序测试,并添加不依赖于所有先前测试的新测试。此外,如果您更改
add_green_fur()
的工作方式,则无需修改数十个测试用例结果。另一个优点是单元测试(如果编写得好)可以准确地告诉您代码失败的位置。
Failed: MyWidget.tests.test_green_fur()
比“widget test failed at line 384”更容易调试,“widget test failed at line 384”通常距离实际故障点几十到几百行。一般来说,单元测试是更好的测试方法。
编辑:
针对您同事的想法,我谨建议他没有参与过包含许多文档测试的大型项目。模型中的文档测试与视图中的文档测试一样糟糕。他们有完全相同的问题(尽管如果有的话,文档测试在模型中更糟糕,因为刷新非常昂贵并且对于彻底的文档测试绝对必要)。 不要低估运行测试所花费的时间成本。
此外,不要混合测试类型,除非你有充分的理由这样做。如果这样做,您很快就会发现自己要加倍测试,或者假设某个功能是在您没有看到的测试套件中进行测试的。
文档测试通常被吹捧为“提供代码应该如何工作的文档”。这很好,但它并不能替代编写具有清晰易读的内联注释的可读代码。如果您需要更多文档,请单独写出来!
您无法编写出同时具有良好文档功能的良好测试。
As your project grows, you'll find that unittests are far better for testing your code.
The Django project itself is in the process of converting all doctests to unittests (we'll be done by the 1.3 release). The reason we're doing this is that prior to this conversion, the order of execution in the test suite would sometimes cause hard to reproduce errors. Sometimes a bit of code would accidentally depend on previously run doctest code. Additionally, switching to unittests has speed the overall test time up, since we can be more judicious about how and when we clear the database.
The other advantage unittests have is that they are MUCH easier to maintain. Because the entire test case is self-contained, you either write another test case, or modify the small, targeted test function to suit.
Doctests tend to work by evolution - you get an instance of your widget, add green fur, make sure the fur is green, add 4 legs, make sure you have 4 legs and green fur, add a thumb, make sure you have a thumb, 4 legs, and green fur, etc... This means that if you want to add a test right after the green fur stage, you have to modify the expected results for every other test case following.
You don't want to do all this rewriting, so you add your new test at the end. Then you add another, and then after a while your tests are so hopelessly jumbled you can't figure out whether or not a specific feature is even tested! With unittests, since each test embodies a specific, concrete and limited idea, it's much easier to re-order the tests logically, and to add a new test that doesn't depend on all the previous ones. Additionally, if you change the way
add_green_fur()
works, you don't have to modify dozens of test case results.The other advantage is that unittests (when written well) tell you precisely where your code failed.
Failed: MyWidget.tests.test_green_fur()
is a lot easier to debug than "widget test failed at line 384", which is often dozens to hundreds of lines away from the actual point of failure.In general, unittests are the better way to test.
Edit:
In response to your colleague's idea, I respectfully suggest that he hasn't worked on a large project with many doctests. Doctests in models are just as bad as in views. They have precisely the same problems (though if anything, doctests are worse in models because
flush
is very expensive and absolutely necessary for thorough doctesting). Don't underestimate the cost of the time taken by running tests.Also, don't mix your test types unless you have a VERY good reason to do so. If you do, you'll very quickly find yourself doubling up tests, or assuming that a function is tested in whichever test suite you don't happen to be looking at.
Doctests are often touted as "providing documentation" for how your code is supposed to work. That's nice, but it's not a substitute for writing readable code with good legible inline comments. If you want further documentation, write it out separately!
You can't write good tests that also function as good documentation.
文档测试非常适合确保您的文档是最新的,但我不会真正使用它们来测试代码。当您更改代码时,您的文档很容易就会过时。
简而言之,使用单元测试来测试代码,使用文档测试来测试文档。
Doctests are great for making sure your documentation is up-to-date, but I wouldn't really use them to test code. It's really easy for your documentation to become out of date as you make changes to your code.
In short, use unit tests to test code and doctests to test documentation.