题
假设你有一个方法:
public void Save(Entity data)
{
this.repositoryIocInstance.EntitySave(data);
}
你会写一个单元的测试吗?
public void TestSave()
{
// arrange
Mock<EntityRepository> repo = new Mock<EntityRepository>();
repo.Setup(m => m.EntitySave(It.IsAny<Entity>());
// act
MyClass c = new MyClass(repo.Object);
c.Save(new Entity());
// assert
repo.Verify(m => EntitySave(It.IsAny<Entity>()), Times.Once());
}
因为后来如果你不改变方法的实施做到更加"复杂"的东西,如:
public void Save(Entity data)
{
if (this.repositoryIocInstance.Exists(data))
{
this.repositoryIocInstance.Update(data);
}
else
{
this.repositoryIocInstance.Create(data);
}
}
...你的单元的测试失败,但它可能不会打破你的申请...
的问题
我应该即使打扰创建单元的测试方法, 没有任何回报类型*或**不要改变任何东西外面的内部模拟?
解决方案
这是真的你的测试是根据您的执行情况,这是一件好事你应该避免的(但这不是真的,简单的有时候...)并不一定是坏事。 但这种测试,预计将突破,甚至如果你改变不破解密码.
你可以有很多办法:
- 创建一个测试,真正进入数据库,并检查,如果国家被改变为预(它 会不会 被一个 单元 测试了)
- 创建一个测试对象的假货数据库,做到行动-存储器(另一个执行你的repositoryIocInstance),并且核实的国家被改变为预期。更改库界面将incurr在改变这个目的。但是,你的接口,不应该改变很多,对吧?
- 看看所有的这太昂贵,并使用你的方法,这可能会产生不必要的破坏试验之后(但是,一旦机会较低,这是确定采取风险)
其他提示
不要忘了单元测试不仅仅是测试代码。这是关于允许您确定的当行为的变化的。
所以,你可能有一些是微不足道。然而,这种实现的变化和可能有副作用。你希望你的回归测试套件来告诉你。
e.g。人们常常说,你不应该测试制定者/吸气,因为他们是微不足道的。我不同意,不是因为他们复杂的方法,但有人可能会无意中无知改变他们,肥手指的情况等。
鉴于这一切,我刚才说的,我肯定会实施上述试验(通过嘲讽,和/或也许是值得考虑的可测性设计的课程,并让他们报告状态等)
问自己两个问题。 “这是什么单元测试的手动相同呢?”和“是否值得自动化?”。在你的情况下,它会是这样的:
什么是手动等效? - 启动调试器 - 步进入“保存”方法 - 步到明年,确保你IRepository.EntitySave里面执行
是否值得自动化?我的回答是“不”。这是从代码100%明显。 从数百个类似的垃圾测试中,我没有看到一个单一的,其会变成是有用的。
一般的经验法则是,您测试所有的东西,这很可能打破。如果您确定,该方法是很简单的(并保持足够简单)不成为一个问题,即让出来与测试。
第二件事是,你应该测试的方法,而不是执行的合同。如果一个变化,而不是应用程序,那么你的测试的测试不正确的事情后,测试失败。测试应涵盖对您的应用程序非常重要的情况。这应该保证,每一个变化的方法不破坏应用程序也不会失败的考验。
简短的回答你的问题是:是的,你一定要测试方法一样,
我假定它是重要该保存方法实际上保存的数据。如果你不写单元测试这一点,那么你怎么知道?
其他人可能会沿着和删除该行的代码调用EntitySave方法,并且没有一个单元测试将失败。后来,你想知道为什么项目从来没有坚持......
在你的方法,你可以说,任何人删除该行只会这样做,如果他们有恶意的意图,但事情是:简单的事情,不一定保持简单,你最好写单元测试事态进一步恶化之前复杂。
这是的不的实现细节,保存方法调用EntitySave在仓库 - 这是预期的行为的一部分,和一个漂亮的重要组成部分,如果我可以这么说。你要确保数据实际被保存。
仅仅因为一个方法不返回值并不意味着它是不值得的测试。一般来说,如果你注意良好的命令/查询分离(CQS),任何void方法应该在预期改变的状态的的东西的。
有时,什么是类本身,但其他时候,也可能是别的东西的状态。在这种情况下,它改变了仓库的状态,那就是你应该是什么测试。
此被称为测试 Inderect输出,而不是的,比较正常的直接输出(返回值)。
关键是要编写单元测试,使他们不打破过于频繁。当使用嘲笑,很容易不小心写的 Overspecified测试的,这就是为什么最有活力的嘲笑(如MOQ)默认的存根的模式,它并不真正的问题是如何多次调用给定的方法。
这一切,和更多,在优良的xUnit测试模式<解释/一>
这不返回任何结果的方法,仍改变了你的应用程序的状态。单元测试,在这种情况下,应该是测试新的状态是否如预期。
“你的单元测试会失败,但它可能不会打破你的应用程序”
这是 - 实际上 - 真正重要的是要知道的。这似乎恼人的和琐碎的,但是当别人开始保持你的代码,他们可能做了一个非常糟糕的变化,以保存和(不大可能),打破了应用程序。
诀窍是优先级。
第一测试重要的东西。当事情慢,添加试验琐碎的东西。
当没有断言的方法中,实质上是断言异常不抛出。
我也与如何测试公共无效myMethod的问题挣扎()。我想,如果你决定了可测试性增加一个返回值,返回值应该代表所有必要突出的事实,看看有什么变化有关应用程序的状态。
public void myMethod()
变为
public ComplexObject myMethod() {
DoLotsOfSideEffects()
return new ComplexObject { rows changed, primary key, value of each column, etc };
}
和不
public bool myMethod()
DoLotsOfSideEffects()
return true;