我有一个消费者类负责消费字符串并决定如何处理它。它可以解析并将解析数据插入数据库中或通知管理员。
以下是我的实施。
public void Consume(string email)
{
if(_emailValidator.IsLocate(email))
{
var parsedLocate = _parser.Parse(email);
// Insert locate in database
}
else if(_emailValidator.IsGoodNightCall(email))
{
// Notify email notifying them that a locate email requires attention.
_notifier.Notify();
}
}
以下是我的单元测试。
// Arrange
var validator = new EmailValidator();
var parser = new Mock<IParser>();
var notifier = new Mock<INotifier>();
var consumer = new LocateConsumer(validator, parser.Object, notifier.Object);
var email = EmailLiterals.Locate;
// Act
consumer.Consume(email);
// Assert
parser.Verify(x => x.Parse(email), Times.Once());
在单元测试中混合模拟和真实实现是代码味道吗?另外,如何总是必须测试方法abc()
是否总是运行一次?每当我在if
块中添加一个函数时添加一个新的单元测试,这似乎是不正确的。似乎如果我继续添加到我的Consume
方法,我就会创建一个陷阱。
谢谢。
答案 0 :(得分:8)
要进行挑剔,单元测试是一种自动测试,可以单独测试一个单元。如果你组合两个或更多单位,它不再是单元测试,它是集成测试。
但是,根据您集成的单元类型,进行大量此类集成测试可能还不错。
Krzysztof Kozmic最近写了一篇关于这篇文章的博客文章,他描述了Castle Windsor has very few unit tests,但是有很多集成测试。 AutoFixture在这些类型的集成测试中也占很大比例。我认为最重要的一点是,作为一般规则,集成不得跨越库边界。
在任何情况下,您都可以将实际实现视为Test Double Continuum的一个极端,正如有些情况下使用Stubs,Mocks,Spies或者假货,还有场景,其中实际的实施可能有意义。
但是,请记住,您不再需要单独测试单元 ,因此您确实在单元之间引入了使每个单独更改变得更加困难强>
总而言之,我仍然认为它是气味,因为它应该永远是一个停下来思考的机会。然而,气味表明只有这一点,有时,一旦你考虑过它,你就可以决定继续前进。
答案 1 :(得分:3)
我会说强烈的是。单元测试应该没有组件之间的依赖关系。
答案 2 :(得分:3)
> Is it a test smell to mix in real implementation and mocks?
这是集成测试(组合2个或更多模块)而不是单元测试(单独测试一个模块)
我的回答是否:我认为在集成测试中进行模拟是可以的。