我有一个非常简单的问题:我一直在为一个具有Context对象的命令对象编写一些单元测试。此上下文中包含一些域实体。
public class Context {
private DomainEntity domainEntity1;
private Dto dto1;
// getters and setters go here...
public boolean isDomainEntityValid() {
// a little bit of logic goes here
}
}
public class Command {
public void execute(Context context) {
// do its logic in here
}
}
DTO和DomainEntity只有setter和getter以及非常简单的验证方法(例如isFirstNameValid()
)。
Context对象确实有逻辑 - 毕竟,它检查上下文是否一致,上下文是否完整,等等。
当单元测试命令对象时,我很清楚上下文应该被模拟 - 但是实体和dto呢?我应该嘲笑他们吗?如果是这样,我将不得不做很多代码,如下面的
doReturn(1L).when(domainEntity1).getId();
doReturn("phil").when(domainEntity1).getName();
换句话说,必须定义getter方法的许多行为。
所以,底线:在单元测试对象时,我应该模拟域实体和DTO吗?
答案 0 :(得分:2)
我认为你可能在这里违反了"Law" of Demeter。我把它放在引号中是因为你不应该遵循这个法律作为建议。
你并没有真正给我们足够的背景来告诉你应该具体改变什么(即:为什么命令需要id和名字?),但是还有其他原则名为Tell, Don't Ask,我认为如果您更改代码,您的代码将变得更容易测试。
答案 1 :(得分:0)
(我想我可以在评论中详细说明一下)
是否需要进行模拟等等都取决于您的系统测试中的逻辑(SUT,在本例中为您的命令)。
模拟/存根的整个想法是我们对SUT的测试不依赖于其他实际代码。因此我们组成适合在测试中使用的模拟/存根,因此测试的有效性仅取决于SUT,而不是其他实际代码(当然,假设您的模拟/存根被正确编写,但这通常不是问题由于其简单性)
所以,如果你的Command逻辑类似于
DomainEntity domain = context.getDomainEntity();
domain.doSomething();
然后是的,您需要对您的域名实体进行模拟。
但是,如果您只是针对上下文,例如:
if (context.isDomainEntityValid()) {
doSomething();
} else {
doAnotherThing();
}
然后没有必要模拟域实体。
还有一点要注意,在模拟框架的帮助下,您可以根据您的SUT逻辑简单地进行存根。您不需要为每个方法进行存根。
因此,如果您的Command只调用domain.doSomething()
,则只需存根此方法。忘记DomainEntity#anotherMethod()
DomainEntity#getId()
。