繁体   English   中英

如何用白盒实例化一个抽象类,以用可以在其中操纵参数的测试逻辑替换方法

[英]How to Whitebox instantiate an abstract class for the purpose of replacing a method with test logic where I can manipulate the arguments

序言( 请阅读 ):

  • 处理遗留代码, 如果没有国会行为我无法重构 (但是我有消息来源)。
  • 这些旧代码与许多抽象类 (及其各种实现)进行交互
  • 模拟还不够,因为我需要拦截发送给抽象方法的方法参数,并在替换(测试)逻辑中对其进行操作
  • 我知道我可以在测试包中扩展这些抽象类,并提供要替换的方法的实现。 但是,此问题的目的是查看是否有解决办法,因为在具有大量抽象方法的抽象类的情况下(例如NIO的SocketChannel),这是一堆无用的样板代码,使单元测试难以理解。
  • 我知道遗留代码的设计很差,并且这不是编写设计良好的单元测试的方式; 没问题。 只知道传统代码无法轻易更改。

问题是 :如何做到这一点(使用PowerMock )而又不会从PowerMock处获得异常,因为该类是抽象的,因此无法实例化该类:

@PrepareForTest({SocketChannel.class})
@RunWith(PowerMockRunner.class)
public class TestThatUsesSocketChannelChannel
{
    replace(method(SocketChannel.class, "read", ByteBuffer.class)).with((proxy, method, args) -> 
    {
        // Line below intercepts the argument and manipulates it 
        ((ByteBuffer) args[0]).clear();
    });
    // The line below throws an exception (because SocketChannel is abstract)
    SocketChannel socketChannel = Whitebox.newInstance(SocketChannel.class);
    // Once here, ideally I can continue my test
}

您可以使用普通的Mockito简单地模拟抽象类:

AbstractClass theMock = mock(AbstractClass.class);

然后通过PowerMock注入抽象类的这个模拟。

找到了答案 :由于SocketChannel是一个抽象类,为了使用Whitebox.newInstance,需要使用ConcreteClassGenerator进行初步准备。 这将创建带有空方法实现的SocketChannel的运行时子级。 请注意,在此之前,我已替换了所需的方法。 结论:这使我可以实例化(即时)抽象类的子级,而无需显式扩展它。 请参阅上面的代码,现在可以与此类中间步骤一起使用:

@PrepareForTest({SocketChannel.class})
@RunWith(PowerMockRunner.class)
public class TestThatUsesSocketChannelChannel
{
    replace(method(SocketChannel.class, "read", ByteBuffer.class)).with((proxy, method, args) -> 
    {
        // Line below intercepts the argument and manipulates it 
        ((ByteBuffer) args[0]).clear();
    });
    // THIS Fixes it: generate a an on-the-fly class that implements stub methods
    // for the ones that are abstract and then (and only then) pass that to Whitebox
    Class<?> concreteSocketChannelClass = new ConcreteClassGenerator().createConcreteSubClass(SocketChannel.class);
    SocketChannel socketChannel = (SocketChannel) Whitebox.newInstance(concreteSocketChannelClass);
    // Once here, ideally I can continue my test
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM