在匿名类中测试方法时,如何使用Powermockito模拟新对象的构造?

我想编写一个JUnit测试来验证以下代码是否使用BufferedInputStream:

public static final FilterFactory BZIP2_FACTORY = new FilterFactory() {

public InputStream makeFilter(InputStream in) {

// a lot of other code removed for clarity

BufferedInputStream buffer = new BufferedInputStream(in);

return new CBZip2InputStream(buffer);

}

};

(FilterFactory是一个接口。)

到目前为止,我的测试如下:

@Test

public void testBZIP2_FactoryUsesBufferedInputStream() throws Throwable {

InputStream in = mock(InputStream.class);

BufferedInputStream buffer = mock(BufferedInputStream.class);

CBZip2InputStream expected = mock(CBZip2InputStream.class);

PowerMockito.spy(InputHelper.BZIP2_FACTORY); // This line fails

whenNew(BufferedInputStream.class).withArguments(in).thenReturn(buffer);

whenNew(CBZip2InputStream.class).withArguments(buffer).thenReturn(expected);

InputStream observed = InputHelper.BZIP2_FACTORY.makeFilter(in);

assertEquals(expected, observed);

}

调用PowerMockito.spy会引发以下消息异常:

org.mockito.exceptions.base.MockitoException: 

Mockito cannot mock this class: class edu.gvsu.cis.kurmasz.io.InputHelper$1

Mockito can only mock visible & non-final classes.

我应该使用什么代替PowerMocktio.spy来设置对whenNew的调用?

回答:

信息很明显:您不能模拟不可见和最终类。简短答案: 匿名 的 ,然后 !

长答案,让我们找出原因吧!

回答:

您实例化一个的匿名类FilterFactory,当编译器看到一个匿名类时,它将创建一个 ,可

类。因此,匿名类无法通过标准方式(即通过Mockito)进行嘲笑。

回答:

好的,现在假设您希望能够通过Powermock模拟该匿名类。当前的编译器使用以下方案编译匿名类:

Declaring class + $ + <order of declaration starting with 1>

模拟匿名类是可能的,但又很脆弱(我是说真的)所以假设匿名类是第11个要声明的类,它将显示为

InputHelper$11.class

因此,您可以潜在地准备测试匿名类:

@RunWith(PowerMockRunner.class)

@PrepareForTest({InputHelper$11.class})

public class InputHelperTest {

@Test

public void anonymous_class_mocking works() throws Throwable {

PowerMockito.spy(InputHelper.BZIP2_FACTORY); // This line fails

}

}

该代码将被编译,但最终将在您的IDE中报告为错误。IDE可能不知道InputHelper$11.class。如此不使用编译类检查代码报告的IntelliJ。

同样,匿名类命名实际上取决于声明的顺序这一事实也是一个问题,当有人在之前添加另一个匿名类时,编号可能会更改。使匿名类保持匿名,如果编译人员决定某一天使用字母或什至随机标识符怎么办!

Eclipse编译器具有不同的编号方案,它始终使用3位数字:

Declaring class + $ + <pad with 0> + <order of declaration starting with 1>

我也不认为JLS明确规定了编译器应如何命名匿名类。

回答:

PowerMockito.spy(InputHelper.BZIP2_FACTORY);  // This line fails

whenNew(BufferedInputStream.class).withArguments(in).thenReturn(buffer);

whenNew(CBZip2InputStream.class).withArguments(buffer).thenReturn(expected);

InputStream observed = InputHelper.BZIP2_FACTORY.makeFilter(in);

PowerMockito.spy返回间谍,它不会更改的值InputHelper.BZIP2_FACTORY。因此,您将需要通过反射来实际设置此字段。您可以使用WhiteboxPowermock提供的实用程序。

回答:

仅用匿名过滤器使用的模拟进行测试就很麻烦BufferedInputStream

回答:

我宁愿编写以下代码:

使用命名类的输入助手,我不会使用接口名称来向用户表明此过滤器的目的!

public class InputHelper {

public static final BufferedBZIP2FilterFactory BZIP2_FACTORY = new BufferedBZIP2FilterFactory();

}

现在过滤器本身:

public class BufferedBZIP2FilterFactory {

public InputStream makeFilter(InputStream in) {

BufferedInputStream buffer = new BufferedInputStream(in);

return new CBZip2InputStream(buffer);

}

}

现在您可以编写这样的测试:

@RunWith(PowerMockRunner.class)

public class BufferedBZIP2FilterFactoryTest {

@Test

@PrepareForTest({BufferedBZIP2FilterFactory.class})

public void wraps_InputStream_in_BufferedInputStream() throws Exception {

whenNew(CBZip2InputStream.class).withArguments(isA(BufferedInputStream.class))

.thenReturn(Mockito.mock(CBZip2InputStream.class));

new BufferedBZIP2FilterFactory().makeFilter(anInputStream());

verifyNew(CBZip2InputStream.class).withArguments(isA(BufferedInputStream.class));

}

private ByteArrayInputStream anInputStream() {

return new ByteArrayInputStream(new byte[10]);

}

}

但是如果您强制CBZip2InputStream只接受,最终可以避免在此测试方案中使用powermock东西BufferedInputStream。通常使用Powermock意味着设计有问题。

希望能有所帮助!

以上是 在匿名类中测试方法时,如何使用Powermockito模拟新对象的构造? 的全部内容, 来源链接: utcz.com/qa/420052.html

回到顶部