如何编写模拟测试方法与日志记录器?



我有以下接口:

public interface SomeProcessor<T> {
void process(Stream<T> someStream);

default <R> R someMap(Function<T, R> function,
T message,
Logger log) {
try {
return function.apply(message);
} catch (Exception exception) {
log.error("Mapping error for message => {}", message, exception);
return null;
}
}
}

并且想通过模拟测试来覆盖方法的日志部分,但不幸的是它总是失败。现在我有了下面的测试:

@ExtendWith(MockitoExtension.class)
class SomeProcessorTest<T> implements SomeProcessor<T> {
@Mock
private Logger mockLogger;
@Override
public void process(Stream<T> someStream) {
}
@Override
public <R> R someMap(Function<T, R> function, T message, Logger log) {
try {
return function.apply(message);
} catch (Exception exception) {
log.error("Mapping error for message => {}", message, exception);
return null;
}
}
@Test
void testWithException() {
SomeProcessor<String> processor = new SomeProcessor <String>() {
@Override
public void process(Stream<String> someStream) {
}
@Override
public <R> R someMap(Function<String, R> function, String message, Logger log) {
throw new RuntimeException("test exception");
}
};
Function<String, Integer> function = Integer::parseInt;
String message = "123";
assertThrows(RuntimeException.class, () -> processor.someMap(function, message, mockLogger));
ArgumentCaptor<String> someCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<Throwable> exceptionCaptor = ArgumentCaptor.forClass(Throwable.class);
verify(mockLogger).error(eq("Mapping error for message => {}"), eq(message), any(RuntimeException.class));
assertEquals("Mapping error for message => {}", someCaptor.getValue());
assertTrue(exceptionCaptor.getValue() instanceof RuntimeException);
}}

但是我总是看到与Wanted but not invoked: mockLogger.error...相关的错误并且我不能在我的界面

中覆盖以下行
catch (Exception exception) {
log.error("Mapping error for message => {}", message, exception);
return null;

我应该在模拟测试中做什么更改以覆盖这些行而不捕获错误?请给我一个忠告。

您的代码中似乎有很多混淆的东西,其背后的原理乍一看并不清楚。mockLogger.error未被调用的问题的根源在于,您正在从测试方法中的匿名类中的接口重写someMap方法的默认实现:

@Override
public <R> R someMap(Function<String, R> function, String message, Logger log) {
throw new RuntimeException("test exception");
}

因为你要测试的代码根本没有被调用。相反,您应该从匿名类中调用super.someMap(...)来调用实际的接口方法默认实现。

当你这样做时,RuntimeException被抛出的断言将失败,因为原始方法消耗异常并返回null-没有抛出异常。

删除抛出异常的断言仍然不会使测试通过,因为您正在测试的函数(Integer::parseInt)应该为您提供的message("123")工作良好,因此catch块将不会被执行,因为没有抛出异常。为了解决这个问题,你应该传递一个会导致解析失败的消息值——而不是一个数字(例如"abc")。

最后-我不明白为什么你的类实现SomeProcessor<T>,但这似乎是多余的,可以删除。

最新更新