如何在用于记录的字符串中避免模拟对象的方法调用?

Vin*_*ega 6 java junit unit-testing easymock powermock

我编写了一个测试方法,其中有一个模拟对象(比如mockA).我可以期待mockA的方法调用实际的程序逻辑.但是,我的程序的一部分也有日志,它需要字符串形式的对象信息.在创建字符串消息时,会在对象上调用一些不必要的方法.因此,在运行测试时,这些方法调用会导致测试失败.这是一个例子.

public class Example {
    public int method(Foo foo) {
       int a = foo.doSomething(); //required for program.
       String logMessage = "foo did something." + foo.getA() + foo.getB().getC();
       logger.log(logFile, logMessage);
       return a;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是示例测试方法.

@Test
public void testMethod() {
   int something = 0;
   Foo mockFoo = EasyMock.createMock(Foo.class);
   expect(mockFoo.doSomething()).andReturn(something);
   EasyMock.replay(mockFoo);
   assertEquals(new Example().method(mockFoo), something);
   EasyMock.verify(mockFoo);
}
Run Code Online (Sandbox Code Playgroud)

这为foo.getA()提供了意外的方法调用.如果我为Foo.class创建了一个漂亮的模拟,它为foo.getB().getC()提供了空指针异常,因为B是foo中的一个对象.我不可能在foo中创建所有对象的漂亮模拟.

反正是否有阻止用于记录的字符串操作?或者,可以做些什么?

谢谢

k.m*_*k.m 2

有两种方法。首先,您模拟正确交互所需的一切Foo(如其他答案中提到的),或者其次,您提取分离依赖项的任何复杂性。

在您的示例中,复杂性在于消息创建。你可以有:

class FooLogMessageFactory {
    public string createLogSomethingMessage(Foo foo) {
        return "foo did something." + foo.getA() + foo.getB().getC();
    }
}
Run Code Online (Sandbox Code Playgroud)

或者整个日志记录部分位于单独的类中:

class FooDedicatedLogger {
    public void logOnSomething(Foo foo) {
        String message = "foo did something." + foo.getA() + foo.getB().getC();
        logger.log(logFile, message);
    }
}
Run Code Online (Sandbox Code Playgroud)

这当然会Example作为构造函数依赖项注入到您的类中。然后在测试中,您可以轻松地模拟它,并完全忘记日志消息的创建(因为它应该是这样,因为它与实际测试方法的作用无关)。

现在,选择哪种方法很大程度上取决于所涉及对象的复杂性(即实际构建日志消息有多困难?比设置一些额外的模拟调用更困难?)。