使用PowerMock编写单元测试,模拟方法无法调用

时间:2017-09-13 11:15:18

标签: java unit-testing junit mockito powermock

我最近学会使用PowerMock为名为Module的类编写单元测试,该类扩展了类Base。它们看起来像这样。

public class Base {
    protected final static ServiceA serviceA;
    protected final static ServiceB serviceB;
    static {
        serviceA = ServiceA.getInstance();
        serviceB = ServiceB.getInstance();
    }
}

public class Module extends Base {
    public DataA methodA() {
        return serviceA.getDataA();
    }
    public DataB methodB() {
        return serviceB.getDataB();
    }
}

我的单元测试看起来像这样:

@PowerMockIgnore("javax.management.*")
@RunWith(PowerMockRunner.class)
@PrepareForTest({Module.class, ServiceA.class, ServiceB.class})
public class ModuleTest {
    private Module module;
    @Mock
    private ServiceA serviceA;
    @Mock
    private ServiceB serviceB;

    @Before
    public void setup() throws Exception {
        MockitoAnnotations.initMocks(this);

        PowerMockito.mockStatic(ServiceA.class);
        PowerMockito.when(ServiceA.getInstance).thenReturn(serviceA);

        PowerMockito.mockStatic(ServiceB.class);
        PowerMockito.when(ServiceB.getInstance).thenReturn(serviceB);

        module = new Module();
        // I spy it because it has other methods I need to mock
        module = PowerMockito.spy(module);
    }

    @Test
    public void methodATest() {
        DataA dataA = new DataA();
        PowerMockito.when(serviceA.getDataA()).thenReturn(dataA);
        DataA data = module.methodA();
        assertEquals(dataA, data);
    }
    @Test
    public void methodBTest() {
        DataB dataB = new DataB();
        PowerMockito.when(serviceB.getDataB()).thenReturn(dataB);
        DataB data = module.methodB();
        assertEquals(dataB, data);
    }
}

一切看起来都很简单但是当我运行ModuleTest时,methodBTest()没有通过。似乎PowerMockito.when(serviceB.getDataB()).thenReturn(dataB)不起作用并且调用了真正的serviceB.getDataB()方法。因此assertEquals(dataB, data)会引发org.junit.ComparisonFailure

如果我将methodBTest()放在methodATest()之前,则methodATest()不会通过。同样的原因。

如果我将PowerMockito.when(serviceA.getDataA()).thenReturn(dataA)PowerMockito.when(serviceB.getDataB()).thenReturn(dataB)放入设置()中,一切都会完美无缺。

这一整天都与我接壤。有谁知道为什么会这样,以及如何解决它?我需要在相应的测试方法中编写的模拟语句,因为我可能会更改返回的值。

1 个答案:

答案 0 :(得分:2)

这是一个涉及(几乎)没有变化的解决方案

@PowerMockIgnore("javax.management.*")
@RunWith(PowerMockRunner.class)
@PrepareForTest({Module.class, ServiceA.class, ServiceB.class})
public class ModuleTest {
    private Module module;

    private static ServiceA serviceA = Mockito.mock(ServiceA.class);

    private static ServiceB serviceB = Mockito.mock(ServiceB.class);

    @BeforeClass
    public static void oneTimeSetup() throws Exception {
        PowerMockito.mockStatic(ServiceA.class);
        PowerMockito.when(ServiceA.class, "getInstance").thenReturn(serviceA);

        PowerMockito.mockStatic(ServiceB.class);
        PowerMockito.when(ServiceB.class, "getInstance").thenReturn(serviceB);
    }

    @Before
    public void setup() throws Exception {
        module = new Module();
        // I spy it because it has other methods I need to mock
        module = PowerMockito.spy(module);
    }

    @Test
    public void methodATest() {
        DataA dataA = new DataA();
        Mockito.when(serviceA.getDataA()).thenReturn(dataA);
        DataA data = module.methodA();
        assertEquals(dataA, data);
    }
    @Test
    public void methodBTest() {
        DataB dataB = new DataB();
        Mockito.when(serviceB.getDataB()).thenReturn(dataB);
        DataB data = module.methodB();
        assertEquals(dataB, data);
    }
}

改变了什么(以及为什么):

  • BaseserviceAserviceB已更改为受保护(Module无法访问,如果私有)
  • 使用"适当" ({1}}
  • 的语法(AFAIK)
  • 使用PowerMockito.when(ServiceA.class, "getInstance").thenReturn(serviceA);并将@BeforeClassserviceA静态设置为"绕过" serviceB
  • 中的静态初始化

使用Junit 4.12,PowerMockito 1.6.2进行测试。

注意:也可以利用Base来实现相同的目标:

@SuppressStaticInitializationFor