2017-09-13 52 views
0

我最近學會使用PowerMock編寫名爲Module的類的單元測試,該類擴展了Base類。他們看起來像這樣。使用PowerMock編寫單元測試,模擬方法無法調用

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

如果我在methodATest()之前加上了methodBTest()methodATest()沒有通過。同樣的道理。

如果我把PowerMockito.when(serviceA.getDataA()).thenReturn(dataA)PowerMockito.when(serviceB.getDataB()).thenReturn(dataB)放在setup()中,一切正常。

這一整天都在我身邊。有沒有人知道這是爲什麼發生以及如何解決它?我需要在相應的測試方法中寫入模擬語句,因爲我可能會更改返回的值。

+2

我建議你刪除PowerMock和使用這樣的:'公共DataA的了methodA(){ 回了methodA( ServiceA.getInstance());用於測試目的* /受保護的數據A方法A(ServiceA服務A){ return serviceA.getDataA(); } – 2017-09-13 11:21:12

+0

@RC。謝謝。這可能是一個解決方案,但實際上我被要求儘量不要修改原來的類。 – IntoCode

回答

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無法訪問,如果私人)
  • 使用「適當」(AFAIK)語法PowerMockito.when(ServiceA.class, "getInstance").thenReturn(serviceA);
  • 使用@BeforeClassBase

用JUnit 4.12,PowerMockito 1.6.2測試製成serviceAserviceB靜態切換至 「分路」 靜態初始化。


注意:它也可以利用@SuppressStaticInitializationFor來達到同樣的目標:

@SuppressStaticInitializationFor(value = "so46196071.Base") // suppress the static in Base (note this is my package name) 
@PowerMockIgnore("javax.management.*") 
@RunWith(PowerMockRunner.class) 
@PrepareForTest({Module.class, ServiceA.class, ServiceB.class}) 
public class ModuleBisTest { 
    private Module module; 

    @Mock 
    private ServiceA serviceA; 

    @Mock 
    private ServiceB serviceB; 

    @Before 
    public void setup() throws Exception { 
     // MockitoAnnotations.initMocks(this); /* this is not needed => done by the runner */ 

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

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

     module = new Module(); 
     Whitebox.setInternalState(Base.class, "serviceA", serviceA); // set serviceA in Base "by hand" 
     Whitebox.setInternalState(Base.class, "serviceB", serviceB); // set serviceB in Base "by hand" 
     // I spy it because it has other methods I need to mock 
     module = PowerMockito.spy(module); 
    } 

    // ... 
+0

非常感謝。我已經嘗試了你的兩個解決方案,並且他們完美地工我決定使用第二種解決方案。 :)是的,兩個「服務」數據字段在原來的「基本」類中被「保護」。這是我的錯誤。 – IntoCode

相關問題