-1

我在需要测试的类中有一个方法。该方法使用我需要模拟的外部类,因此外部类不会被测试或执行其依赖项。特殊的挑战是:外部类的一个方法被覆盖。方法如下所示:

public void fetchLocalData(final String source, final ObservableEmitter<String> destination) {
   final List<String> options = Arrays.asList("recursive","allFiles","includeDir");
   // This class comes from a package
   final DirScan dirscan = new DirScan(source, options) {
       @Override
       protected Action getResult(final String result) {
           destination.onNext(result);
           return Action.Continue;
       }
   };
   dirscan.scan();
   destination.onComplete();
}

我试过了:

    DirScan scanner = mock(DirScan.class);
    when(scanner.scan()).thenReturn("one").thenReturn("two");

那没有用。我想念什么?我需要如何重构才能使其可测试?

4

1 回答 1

0

如果您想dirscan用模拟(或间谍)替换 ,您需要重构您的类,使其成为依赖项或参数。或者,您可以使用PowerMockito'swhenNew功能。

让我们假设您更改了您的类,而不是String source您提供DirScan对象作为参数。您需要在其他地方为 dirscan 提供某种创建方法(可能是一种static方法)。

final List<String> options = Arrays.asList("recursive","allFiles","includeDir");

public DirScan createDirScan(String source) {

   // This class comes from a package
   final DirScan dirscan = new DirScan(source, options) {
       @Override
       protected Action getResult(final String result) {
           destination.onNext(result);
           return Action.Continue;
       }
   };

   return dirscan;
}
public void fetchLocalData(final DirScan dirscan, final ObservableEmitter<String> destination) {
    dirscan.scan();
    destination.onComplete();
}

从您的问题来看,您似乎想测试与目标对象的交互,因此您不想模拟该dirscan对象(因为如果您这样做,将不会有任何交互)。您可能想使用 aspy并且只替换该getResult方法。

现在,在您的测试中,您可以简单地spydirscan对象传递 a 并使用 定义它的行为thenAnswer

final ObservableEmitter<String> destination = ...

DirScan dirscan = Mockito.spy(createDirScan(source, destination));

Mockito.when(dirscan.getResult(Mockito.any(String.class))).thenAnswer((Answer<Action>) invocation -> {
    String result = invocation.getArgument(0);
    destination.onNext(result);

    return Action.Continue;
});

classUnderTest.fetchLocalData(dirscan, destination);

此时您可能会注意到,最好不要使用间谍而只使用真实DirScan对象。使用spy来做你打算用覆盖的方法做的事情对我来说似乎有点过头了。

真实的对象必须工作才能使这个测试有价值,所以你不妨测试真实的东西。

于 2020-01-16T10:03:48.543 回答