Spo*_*ike 97 language-agnostic tdd integration-testing unit-testing testing-strategies
我相信大多数人都在编写大量的自动化测试,而且在进行单元测试时你也遇到了一些常见的陷阱.
我的问题是你是否遵循任何编写测试的行为规则以避免将来出现问题?更具体一点:良好单元测试的属性是什么,或者您如何编写测试?
鼓励语言不可知的建议.
Gis*_*shu 93
让我首先插入源代码 - 使用JUnit在Java中进行语用单元测试(还有一个带有C#-Nunit的版本......但是我有这个...它的大部分都是不可知的.推荐.)
好的测试应该是一个TRIP(首字母缩略词不够粘 - 我在书中打印出了cheatsheet,我不得不拔出以确保我做对了..)
专业:从长远来看,您将拥有与生产一样多的测试代码(如果不是更多),因此您的测试代码遵循相同的良好设计标准.精心设计的方法 - 具有意图揭示名称的类,无重复,具有良好名称的测试等.
好的测试也快速运行.任何需要超过半秒才能运行的测试......需要加以研究.测试套件运行所需的时间越长,运行的频率就越低.开发人员试图在两次运行之间潜行的变化越多......如果有什么破坏......需要更长的时间来确定哪个变化是罪魁祸首.
2010-08更新:
除此之外,其他大多数都是减少低效益工作的准则:例如"不要测试你不拥有的代码"(例如第三方DLL).不要去测试getter和setter.密切关注成本效益比或缺陷概率.
Sör*_*lau 42
wom*_*omp 41
这里的大多数答案似乎都是针对单元测试的最佳实践(何时,何地,为什么以及什么),而不是实际编写测试本身(如何).由于问题在"如何"部分看起来非常具体,我想我会发布这个,取自我在公司进行的"棕色包"演示.
1.使用长的描述性测试方法名称.
- Map_DefaultConstructorShouldCreateEmptyGisMap()
- ShouldAlwaysDelegateXMLCorrectlyToTheCustomHandlers()
- Dog_Object_Should_Eat_Homework_Object_When_Hungry()
Run Code Online (Sandbox Code Playgroud)
2.以Arrange/Act/Assert风格编写测试.
3.始终使用断言提供失败消息.
Assert.That(x == 2 && y == 2, "An incorrect number of begin/end element
processing events was raised by the XElementSerializer");
Run Code Online (Sandbox Code Playgroud)
4.评论测试的原因 - 业务假设是什么?
/// A layer cannot be constructed with a null gisLayer, as every function
/// in the Layer class assumes that a valid gisLayer is present.
[Test]
public void ShouldNotAllowConstructionWithANullGisLayer()
{
}
Run Code Online (Sandbox Code Playgroud)
5.每个测试必须始终恢复其接触的任何资源的状态
Men*_*elt 17
记住这些目标(改编自Meszaros的xUnit Test Patterns一书)
有些事情可以让这更容易:
不要忘记您也可以使用xUnit框架进行集成测试,但要将集成测试和单元测试分开
伟大的单元测试的一些属性:
当测试失败时,应该立即明确问题所在.如果必须使用调试器来追踪问题,那么您的测试就不够精确.每次测试只有一个断言有助于此.
重构时,任何测试都不会失败.
测试应该运行得如此之快,以至于您可以毫不犹豫地运行它们.
所有测试都应该通过; 没有非确定性的结果.
单元测试应该是一个很好的因素,就像你的生产代码一样.
@Alotor:如果您建议库只应在其外部API上进行单元测试,我不同意.我想要为每个类进行单元测试,包括我不向外部调用者公开的类.(但是,如果我觉得需要为私有方法编写测试,那么我需要重构.)
编辑:有关于"每次测试一个断言"引起的重复的评论.具体来说,如果您有一些代码来设置场景,然后想要对其进行多次断言,但每次测试只有一个断言,则可能会在多个测试中复制设置.
我不接受这种方法.相反,我在每个场景中使用测试装置.这是一个粗略的例子:
[TestFixture]
public class StackTests
{
[TestFixture]
public class EmptyTests
{
Stack<int> _stack;
[TestSetup]
public void TestSetup()
{
_stack = new Stack<int>();
}
[TestMethod]
[ExpectedException (typeof(Exception))]
public void PopFails()
{
_stack.Pop();
}
[TestMethod]
public void IsEmpty()
{
Assert(_stack.IsEmpty());
}
}
[TestFixture]
public class PushedOneTests
{
Stack<int> _stack;
[TestSetup]
public void TestSetup()
{
_stack = new Stack<int>();
_stack.Push(7);
}
// Tests for one item on the stack...
}
}
Run Code Online (Sandbox Code Playgroud)
测试应该是孤立的.一项测试不应该依赖于另一项测试.更进一步,测试不应该依赖外部系统.换句话说,测试你的代码,而不是代码的代码取决于on.You可以测试这些交互为您的集成测试或功能测试的一部分.
良好的测试需要维护.
我还没有弄清楚如何在复杂环境中这样做.
随着您的代码库开始涉及数百个或数百万行代码,所有教科书都开始脱口而出.
良好的架构可以控制一些交互爆炸,但随着系统变得越来越复杂,自动化测试系统随之增长.
这是您开始处理权衡的地方:
你还需要决定:
你在哪里存储代码库中的测试用例?
我可以永远继续下去,但我的观点是:
测试需要可维护.
我在这篇MSDN杂志文章中回顾了这些原则,我认为对任何开发人员都很重要.
我定义"好"单元测试的方式是,它们是否具有以下三个属性: