在测试类中没有参数的测试方法

时间:2014-07-25 16:34:34

标签: java unit-testing testing junit mockito

我有一个类,它接收带有效负载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?
            }
        }
    }
}

3 个答案:

答案 0 :(得分:1)

您可以使用Mockito Matchers进行验证。

如果您只关心使用某些 Entity调用该方法,则可以使用

验证该方法
verify(daoInterface).insert(any(Entity.class));

如果您关心哪个EntityEntity类有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'确实返回了一个值,这只是一个例子。