我有一个类,它接收带有效负载String的消息。 然后拆分有效负载并用于创建一个实体,该实体将传递给DAOInterface以保持。
如何测试daoInterface.insert(entity)
来电?
模拟DAOInterface,然后验证对DAO的调用是否需要测试类中的实体,即
verify(daoInterface).insert(entity);
这是一个糟糕的设计,即在这个阶段创建实体吗?应该将Sting []拆分传递给DAOImplementaion并在那里进行初始化。示例问题,
public class ServiceClass {
@AutoWire
private DAOInterface daoInterface;
public void serviceMessage(Message<String> message) {
MessageHeaders mh = new MessageHeaders(message.getHeaders());
String[] split = ((String) mh.get("payload")).split("_");
code omitted
...
String type = mh.get("WhatType");
Entity entity = new Entity(split[0], split[1], split[2]);
if (type.equals("one"))
{
daoInterface.insert(entity); //How to test?
}
else
{
if (type.equals("two"))
{
doaInterface.modify(entity); //How to test?
}
}
}
}
答案 0 :(得分:1)
您可以使用Mockito Matchers进行验证。
如果您只关心使用某些 Entity
调用该方法,则可以使用
verify(daoInterface).insert(any(Entity.class));
如果您关心哪个Entity
,Entity
类有equals
方法,您可以创建一个与创建的实体相同的实体,并使用
verify(daoInterface).insert(eq(expectedEntity);
如果它比任何一种情况都复杂,你也可以编写自己的论证匹配。
答案 1 :(得分:0)
您可以做的最简单的事情是将另一个协作者注入服务,该服务将有效负载转换为实体。这样您就可以控制对象的创建(Inversion of Control)。注入ServiceClass
的下面示例应该可以完成这项任务:
interface PayloadTransformer {
public Entity transform(String payload);
}
通过这种方式,您的代码将易于测试,您可以分担责任,这通常是一件好事。看看Single Responsibility principle
将转换逻辑推向dao几乎不是一个好主意。
顺便说一句。你可以写else if
而无需额外的括号和缩进。它更具可读性:
if (a) {
// do something
} else if (b) {
// do something
} else {
// do something
}
最后一条建议ServiceClass是一个非常糟糕的类名。这个词在这里是多余的。只需将其命名为服务, EntityService , MessageService 或适合您的情况。 我也不会用后缀*接口来命名字段。我假设下面是注入的一些实现。更好地命名为 entityDao 或只是 dao 。它取决于你:)
答案 2 :(得分:0)
如果您使用PowerMock,之类的测试框架,则可以在测试中invoke private constructors and private methods。这样可以很容易地注入模拟对象,例如模拟DAOInterface
,这样您可以在以后检索它并测试它已被调用。
例如,在PowerMock中,要调用私有构造函数:
public class ServiceClass{
@Autowire
private final DAOInterface dao;
public ServiceClass() {
}
private ServiceClass(DAOInterface dao) {
this.dao = dao;
}
}
你只需:
PrivateConstructorInstantiationDemo instance = WhiteBox.invokeConstructor(
PrivateConstructorInstantiationDemo.class,
new MockDAOInterface() );
因此,如果您使用上面的依赖注入框架,这很好地吻合了。您通常不会在测试期间使用依赖项注入,因为它通常需要使用大量配置来引导大量代码。
通过添加单个私有构造函数,可以避免破坏封装,但在测试期间,您仍可以使用PowerMock等测试框架将模拟对象注入代码中。这被认为是最佳做法。
您可以打破封装并向SeviceClass添加可公开访问的方法或ctors,但如果您的设计不需要它们,那么仅将它们添加到测试中并不是一个好习惯。这就是为什么人们在Mockito和PowerMock等框架中绕过封装的原因。这不仅仅是对私有代码的躲闪,而是因为你想要在仍然能够测试的同时保持封装。
编辑:
如果您不熟悉制作模拟对象,则应该对该主题进行一些Google搜索。拥有它是非常普遍和良好的技能。使用上面的代码,您可以创建自己的模拟对象。但是制作模拟很常见,大多数测试框架都会为你做这件事。
例如,在PowerMock中,我只看了他们的page on making mocks here。你可以像这样做一个模拟
DAOInteface myMock = createMock(DAOInterface.class);
然后,您可以要求模拟验证方法是否被调用:
expect(myMock.someMethod());
现在模拟'期望'要调用该方法,如果不是,它将为您的测试生成错误。实际上很甜蜜。
您还可以从通话中返回值:
expect(myMock.insert()).andReturn("Test succeeded");
因此,当您调用该方法时,您的代码会看到值“Test succeeded”。我没有看到'insert'确实返回了一个值,这只是一个例子。