6

我编写了一个测试方法,其中有一个模拟对象(比如 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;
    }
}

这是示例测试方法。

@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);
}

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

有没有办法防止这种用于记录的字符串操作?或者,可以做些什么?

谢谢

4

3 回答 3

2

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

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

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

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

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

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

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

于 2013-10-17T11:55:27.017 回答
1

莫基托怎么样?在此处查看返回深度存根的可能性

(尤其是为什么你不应该这样做的部分;)),那么你可以把你的测试写成:

@Test
public void testMethod() {
   int something = 0;
   Foo mockFoo = mock(Foo.class, RETURNS_DEEP_STUBS);
   when(mockFoo.doSomething()).thenReturn(something);
   assertEquals(new Example().method(mockFoo), something);
   verify(mockFoo);
}

我在 Easymock 中找不到任何类似的技术,这里的答案表明没有任何东西。


另一个想法:

如果您可以重构代码并使用 SLF4J 作为日志框架,则可以在 logger 调用中编写 Logging 消息,并且仅根据 Loglevel 执行此操作。在测试中将您的日志级别提高到 NONE 并且 foo.getA() ... 将不会被执行。

public int method(Foo foo) {
   int a = foo.doSomething(); //required for program.
   logger.error("foo did something {}" , foo.getA() + foo.getB().getC());
   return a;
}
于 2013-10-17T12:03:51.143 回答
0

你可以做类似的事情

B b = EasyMock.createMock(B.class);

期望(mockFoo.getB()).andReturn(b);

所以foo.getB()会给你模拟对象。所以不会有NPE。

于 2013-10-17T10:06:47.073 回答