2017-09-13 54 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

相关问题