【问题标题】:Multiple RunWith Statements in jUnitjUnit 中的多个 RunWith 语句
【发布时间】:2015-07-26 15:57:30
【问题描述】:

我编写单元测试并希望将JUnitParamsRunnerMockitoJUnitRunner 用于一个测试类。

很遗憾,以下方法不起作用:

@RunWith(MockitoJUnitRunner.class)
@RunWith(JUnitParamsRunner.class)
public class DatabaseModelTest {
  // some tests
}

有没有办法在一个测试类中同时使用 Mockito 和 JUnitParams?

【问题讨论】:

标签: java unit-testing junit


【解决方案1】:

您不能这样做,因为根据规范,您不能在同一个带注释的元素上两次放置相同的注释。

那么,解决方案是什么?解决方案是只将一个@RunWith() 与您无法忍受的跑步者放在一起,然后用其他东西替换另一个。在您的情况下,我猜您将删除 MockitoJUnitRunner 并以编程方式执行它的功能。

事实上它唯一能做的就是运行:

MockitoAnnotations.initMocks(test);

在测试用例的开头。所以,最简单的解决办法就是把这段代码放到setUp()方法中:

@Before
public void setUp() {
    MockitoAnnotations.initMocks(this);
}

我不确定,但可能您应该避免使用标志多次调用此方法:

private boolean mockInitialized = false;
@Before
public void setUp() {
    if (!mockInitialized) {
        MockitoAnnotations.initMocks(this);
        mockInitialized = true;  
    }
}

不过更好的是,可以使用 JUnt 的规则来实现可重用的解决方案。

public class MockitoRule extends TestWatcher {
    private boolean mockInitialized = false;

    @Override
    protected void starting(Description d) {
        if (!mockInitialized) {
            MockitoAnnotations.initMocks(this);
            mockInitialized = true;  
        }
    }
}

现在只需将以下行添加到您的测试类中:

@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();

你可以用任何你想要的运行器运行这个测试用例。

【讨论】:

  • mockInitialized 的检查错误。您希望每次测试都有一个新的模拟。
  • @BetaRide,这取决于您的需求。有时您想每次都初始化 mock,有时则不需要。
  • 如果你想为每个类文件设置一次,你可以使用 BeforeClass 而不是 Before,每个测试文件只会调用一次。
【解决方案2】:

从 JUnit 4.7 和 Mockito 1.10.17 开始,此功能已内置;有一个org.mockito.junit.MockitoRule 类。您可以简单地导入它并添加行

@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();

到你的测试班。

【讨论】:

  • 对于旧版本的 Mockito(似乎降到 1.10.5),您必须使用:@Rule public MockitoJUnitRule mockito = new MockitoJUnitRule(this);
  • MockitoAnnotations.initMocks(this) 创建模拟的速度非常慢。最有效的方法是使用 @Runwith(MockitoJunitRunner.class)
  • 但是正如OP提到的,你不能使用两个@RunWith语句,他需要使用另一个。
【解决方案3】:

此解决方案适用于所有可能的跑步者,而不仅仅是这个 mockito 示例。例如;对于 Spring,只需更改运行器类并添加必要的注释即可。

@RunWith(JUnitParamsRunner.class)
public class DatabaseModelTest {

    @Test
    public void subRunner() throws Exception {
        JUnitCore.runClasses(TestMockitoJUnitRunner.class);
    }

    @RunWith(MockitoJUnitRunner.class)
    public static class TestMockitoJUnitRunner {
    }
}

DatabaseModelTest 将由 JUnit 运行。 TestMockitoJUnitRunner 依赖于它(通过逻辑),它将在调用 JUnitCore.runClasses(TestMockitoJUnitRunner.class) 期间以 @Test 方法在 main 的 inside 中运行。这种方法保证了主运行器在static class TestMockitoJUnitRunner子运行器运行之前正确启动,有效地实现了多个嵌套的@RunWith注解与依赖的测试类。

同样在https://bekce.github.io/junit-multiple-runwith-dependent-tests

【讨论】:

  • 在不检查结果的情况下调用JUnitCore.runClasses(),您可能会掩盖内部测试中的错误。 assert(JUnitCore.runClasses(TestMockitoJUnitRunner.class).wasSuccessful());至少会把错误报告给你
【解决方案4】:

自 PowerMock 1.6 发布以来,您可以轻松地做到这一点

@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(JUnitParamsRunner.class)
public class DatabaseModelTest {
  // some tests
}

这里解释https://blog.jayway.com/2014/11/29/using-another-junit-runner-with-powermock/

【讨论】:

    【解决方案5】:

    在我的例子中,我试图在 spring bean 中模拟一些方法和

    MockitoAnnotations.initMocks(test);
    

    不起作用。相反,您必须在您的 xml 文件中定义该 bean 以使用模拟方法构造,如下所示。

    ...
    <bean id="classWantedToBeMocked" class="org.mockito.Mockito" factory-method="mock">
        <constructor-arg value="com.fullpath.ClassWantedToBeMocked" />
    </bean>
    ...
    

    并在您的测试类中添加自动装配的 bean,如下所示。

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations="file:springconfig.xml")
    public class TestClass {
        ...
        @Autowired
        private ClassWantedToBeMocked classWantedToBeMocked;
        ...
        when(classWantedToBeMocked.methodWantedToBeMocked()).thenReturn(...);
        ...
    }
    

    【讨论】:

      【解决方案6】:

      查看此链接https://bekce.github.io/junit-multiple-runwith-dependent-tests/ 使用这种方法,我结合了 @RunWith(Parameterized.class) - 外流道 - 与 @RunWith(MockitoJUnitRunner.class) - 内流道。我必须添加的唯一调整是使外部类/运行器中的成员变量为静态,以使内部/嵌套运行器/类可以访问它们。祝你好运,尽情享受吧。

      【讨论】:

        【解决方案7】:

        我想同时运行 SWTBotJunit4ClassRunnerorg.junit.runners.Parameterized,我有参数测试,我想在 SWT 测试失败时截屏(截图功能由 SWTBotJunit4ClassRunner 提供)。 @bekce 的回答很棒,首先想走那条路,但通过争论要么很古怪。或者在子类中进行参数化并丢失确切测试通过/失败的信息,并且只有最后一个屏幕截图(因为屏幕截图名称从测试本身获取名称)。所以不管怎样,它有点乱。

        在我的例子中,SWTBotJunit4ClassRunner 很简单,所以我克隆了这个类的源代码,给它起了我自己的名字 ParametrizedScreenshotRunner 并且原来的地方是扩展 TestRunner,我的类正在扩展 Parameterized 类,所以本质上我可以使用我自己的跑步者而不是前两个。归结为我自己的跑步者在参数化跑步者之上扩展,同时在其上实现截图功能,现在我的测试使用这个“混合”跑步者,所有测试都按预期工作(无需更改测试内部的任何内容)。

        这就是它的样子(为简洁起见,我从列表中删除了所有 cmets):

        package mySwtTests;
        
        import org.junit.runners.Parameterized;
        import org.eclipse.swtbot.swt.finder.junit.ScreenshotCaptureListener;
        import org.junit.runner.notification.RunListener;
        import org.junit.runner.notification.RunNotifier;
        
        public class ParametrizedScreenshotRunner extends TestRu Parameterized {
        
            public ParametrizedScreenshotRunner(Class<?> klass) throws Throwable {
                super(klass);
            }
        
            public void run(RunNotifier notifier) {
                RunListener failureSpy = new ScreenshotCaptureListener();
                notifier.removeListener(failureSpy); // remove existing listeners that could be added by suite or class runners
                notifier.addListener(failureSpy);
                try {
                    super.run(notifier);
                } finally {
                    notifier.removeListener(failureSpy);
                }
            }
        }
        

        【讨论】:

          【解决方案8】:

          虽然在 JUnit 4 中没有解决方案,但可以在 JUnit 5 中注册多个扩展:

          @ExtendWith(MockitoExtension.class)
          @ExtendWith(AnotherExtension.class)
          public class MyTest {
            // some tests
          }
          

          请注意,JUnitParams 框架内置在 JUnit 5 中。

          【讨论】:

            【解决方案9】:

            你也可以试试这个:

            @RunWith(JUnitParamsRunner.class)
            public class AbstractTestClass {
              // some tests
            }
            
            @RunWith(MockitoJUnitRunner.class)
            public class DatabaseModelTest extends AbstractTestClass {
              // some tests
            }
            

            【讨论】:

            • 这个不行,只会处理子类注解。
            • 不起作用 - 只会考虑 MockitoJUnitRunner 注释
            猜你喜欢
            • 2015-01-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多