【问题标题】:PowerMock test passes then failsPowerMock 测试通过然后失败
【发布时间】:2015-10-06 18:25:02
【问题描述】:

为什么我的单元测试在独立运行时通过,但在运行多个测试时失败?

当我执行单个单元测试时,我的测试将成功模拟并返回预期结果。但是,当我运行所有单元测试时,我之前通过的测试将失败。

一次测试运行

shouldDoThisAgain() - 通过

多次测试运行

shouldDoThis() - 通过

shouldDoThisAgain() - 失败

shouldDoThisAgainAgain() - 失败

我的测试:

@PrepareForTest({OtherMethods.class})
@PowerMockIgnore("javax.management.*")
@RunWith(PowerMockRunner.class)
public class DbTest {
    @Test
    public void shouldDoThis() throws Exception() {
        Dal dalMock = mock(Dal.class)
        PowerMockito.whenNew(Dal.class).withAnyArguments().thenReturn(dalMock)
        List<Result> results = new ArrayList<Result>();
        results.add(new Result(1,2,3));
        when(dalMock.getResults()).thenReturn(results)
        assertTrue(Wrapper.MY_WRAPPER.run()); 
    }
    @Test
    public void shouldDoThisAgain() throws Exception() {
        Dal dalMock = mock(Dal.class)
        PowerMockito.whenNew(Dal.class).withAnyArguments().thenReturn(dalMock)
        List<Result> results = new ArrayList<Result>();
        results.add(new Result(2,3,4));
        when(dalMock.getResults()).thenReturn(results)
        assertTrue(Wrapper.MY_WRAPPER.run());
    }
    @Test
    public void shouldDoThisAgainAgain() throws Exception() {
        Dal dalMock = mock(Dal.class)
        PowerMockito.whenNew(Dal.class).withAnyArguments().thenReturn(dalMock)
        List<Result> results = new ArrayList<Result>();
        results.add(new Result(6,5,3));
        when(dalMock.getResults()).thenReturn(results)
        assertTrue(Wrapper.MY_WRAPPER.run());
    }
}

我的课:

public class Wrapper {
    // not Runnable
    public static final MyWrapper MY_WRAPPER = new MyWrapper(...){
        @Override
        public boolean run() {
           // returns empty list when the test is alone
           // returns 'results' variable when ran with other tests alone
           List<Result> results = OtherMethods.getDal().getResults();
           return !results.isEmpty()
        }
    };  
}

public class OtherMethods {
     private static final Logger LOGGER = LogManager.getLogger(OtherMethods.class);

     public static Dal dal;
     
     static Dal getDal() {
         if (dal == null) {
             try {   
                 dal = new Dal();
             } catch (Exception e) {
               LOGGER.fatal("DB Connection could not be created for Geonames");
               LOGGER.fatal(e);
           }
        }
        return dal;
    }
}

【问题讨论】:

  • 您对OtherMethods 的实现,尤其是getDal() 是一个非常糟糕的主意。

标签: java unit-testing mocking mockito powermock


【解决方案1】:

我为我们的项目找到了解决方案。我写了一个 Logger 类,它调用 Android 的内部静态 Log 方法。我的一些测试没有直接测试 Log 类。当我忽略所有这些时,基于 powermockito 的测试变绿了。但是当这些其他测试运行时,基于 powermockito 的测试会失败。有时。

这种方法会失败(不稳定):

@RunWith(PowerMockRunner.class)
@PrepareForTest({Log.class})    // WARNING: HERE BE DRAGONS!
public class MyTest {

    @Test
    public void testMethodThatDoesNotUseStatics() {
        // ...
    }

    @Test
    public void usesStatics() {
        // ...
    }

}

然后我发现你可以用@PrepareForTest注释每个测试方法,像这样:

@RunWith(PowerMockRunner.class)
public class MyTest {

    @Test
    public void testMethodThatDoesNotUseStatics() {
        // ...
    }

    @Test
    @PrepareForTest({Log.class})    // that's the way :)
    public void usesStatics() {
        // ...
    }

}

现在测试又变绿了。是的非片状测试! :)

【讨论】:

  • 与 Powermock + easymock + junit 的情况类似。也只有第一次测试成功。将 {@PrepareForTest} 移到每次测试之前都有帮助。但是应该这样吗?这不是 PowerMock 中的某种错误吗?
【解决方案2】:

检查@PrepareForTest({OtherMethods.class}) 放在类级别时的行为...

已删除以回应 OP 的评论
我刚刚注意到别的东西:
我假设您的 MyWrapper 类是 Runnable,因此它只能 run() 一次,您需要为每次测试重新初始化它
已删除

编辑: 那么你的问题在于你的OtherMethods类的实现,你没有在这里展示它,这让我们很难

【讨论】:

  • 抱歉,它无法运行,我的错。我试图将它概括为一个可以执行的函数。
  • 你是对的,这是我对 OtherMethods 类的实现。好吧。我在原始帖子中没有正确引用代码。我根据问题的发生方式对其进行了修改。基本上,我在OtherMethods.class 中对我的 dal 做了一个单例模拟。但是,在我的测试中,我引用了本地 dalMock 对象,而不是 RuleMethods 中的模拟对象。我有根据的猜测是我指向了错误的对象。非常感谢。
  • 附带说明:当您找到有用的答案或 cmets 时,将它们标记/标记为有用...
  • 在我的“声誉”提高之前做不到。
【解决方案3】:

尝试这样做

@PrepareForTest({OtherMethods.class})
@PowerMockIgnore("javax.management.*")
@RunWith(MowerMockRunner.class)
public class DbTest {
@Before
public void setUp(){
     Dal dalMock = mock(Dal.class);        
PowerMockito.whenNew(Dal.class).withAnyArguments().thenReturn(dalMock);
List<Result> results = new ArrayList<Result>();
    results.add(new Result(1,2,3));
    when(OtherMethods.getDal().getResults()).thenReturn(results)
}
@Test
public void shouldDoThis() throws Exception() {

    assertTrue(Wrapper.MY_WRAPPER.run());
}
@Test
public void shouldDoThisAgain() throws Exception() {

    assertTrue(Wrapper.MY_WRAPPER.run());
}
@Test
public void shouldDoThisAgainAgain() throws Exception() {

    assertTrue(Wrapper.MY_WRAPPER.run());
}
}

【讨论】:

  • 我确实这样做了。它仍然重复相同的行为(假设我在每个 @Test 中更改了 List&lt;Result&gt; results)。
  • 你不必重复 when(OtherMethods.getDal().getResults()).thenReturn(results);每次更改结果时声明。只需使用 .thenReturn(results1).thenReturn(results2) 等等。由于您正在测试 ! results.isEmpty() 在每个方法中,您都可以将这三个 assertTrues 放入一个测试方法中。不需要三个单独的方法
猜你喜欢
  • 1970-01-01
  • 2019-07-31
  • 2014-04-27
  • 2021-03-26
  • 1970-01-01
  • 1970-01-01
  • 2015-07-08
  • 2013-09-09
  • 1970-01-01
相关资源
最近更新 更多