无法在静态方法 Powermock 中模拟函数

Unable to Mock functions inside static method Powermock

我正在使用 junit 和 mockito 为下面的代码编写单元测试

 public class Abc implements Runnable
    {
        private static ServerSocket server;  
        private static int port;      
        public Abc(int cPort)
        {
            port = cPort;
        }

        public void run()
        {
            init();
        }

        public static void init()
        {
            try {
                server = new ServerSocket(port);
                ...something...
                client.close();
                } 
            }
            catch(IOException e)
            {   
                System.out.println("Exception inside init()...");
                e.printStackTrace();
            }
        }
    };

我写的单元测试

@RunWith(PowerMockRunner.class)
@PrepareForTest({ServerSocket.class})
public class abcTest {

    @Mock (name = "server") //same name as private var.
    ServerSocket mockServer;        
    @InjectMocks
    Abc abc;

    @Test
    public void testInit() throws Exception {
        int port = 1880;
        Socket mockClient = Mockito.mock(Socket.class);  
        PowerMockito.whenNew(ServerSocket.class).
                withArguments(anyInt()).thenReturn(mockServer);         
        abc = new Abc(port);
        Abc.init();         
        PowerMockito.verifyNew(ServerSocket.class).withArguments(port);
    }
};

但调用总是转到原始函数定义。我将 junit 4.11 与 mockito 2.28.2 和 powermockito 2.0.2 一起使用。很长一段时间后,我正在使用 java。现在感觉有点像新的。如果代码中有任何错误,请纠正我。

您需要更改 PrepareForTest 注释 至 @PrepareForTest({Abc.class}).

来自 PowerMockito docu:

This annotation tells PowerMock to prepare certain classes for testing. Classes needed to be defined using this annotation are typically those that needs to be byte-code manipulated

在这种情况下,指的是创建 ServerSocket 的新实例的 class。
ServerSocket 本身是一个 non-final public class 不需要 PowerMockito 的特殊处理(相反 Mockito 可以自己处理这个 class)。


您还可以更改测试以执行以下操作:

@Test
public void testInit() throws Exception {
    int port = 1880;

    ServerSocket mockServer = Mockito.mock(ServerSocket.class);

    PowerMockito.whenNew(ServerSocket.class)
                .withArguments(Mockito.anyInt()).thenReturn(mockServer);

    Abc.port = port;
    Abc.init();     

    PowerMockito.verifyNew(ServerSocket.class).withArguments(port);
}

  • (这第一点与测试成功与否无关)
    我不知道你为什么将对象和静态方法的行为混合在一起,但我认为你应该改变它。

    在测试中而不是创建一个 ABC 对象,只需设置直接静态端口变量。
    或者将整个 ABC class 更改为一个对象。

  • @InjectMocks 对我来说失败了,因为没有默认构造函数
    (实际上我在尝试执行您的代码时在控制台中收到一条错误消息)

  • 此外,您在测试中创建了一个新的 ABC 实例,这将覆盖注释所做的事情。此外,由于 server 是在 init 调用期间创建的,因此无需为其注入模拟。

  • powermockito 2.0.2 实际上取决于 junit 4.12,所以我不确定降级到旧版本可能会有什么影响。

  • Socket mockClient 似乎与您发布的代码有些无关,因此我将其从答案中的示例中删除,但是当您使用 client (我假设是你的 Socket) 在你的代码中,你可能还需要为此做一些模拟,并相应地为方法提供模拟。