Java jUnit中的多个RunWith语句
我编写单元测试,并希望对一个测试类使用Java jUnit中的多个RunWith语句,java,unit-testing,junit,Java,Unit Testing,Junit,我编写单元测试,并希望对一个测试类使用junitpamsrunner和MockitoJUnitRunner 不幸的是,以下方法不起作用: @RunWith(MockitoJUnitRunner.class) @RunWith(JUnitParamsRunner.class) public class DatabaseModelTest { // some tests } 有没有办法在一个测试类中同时使用Mockito和junitpams?您不能这样做,因为根据规范,您不能在同一个带注释的元
junitpamsrunner
和MockitoJUnitRunner
不幸的是,以下方法不起作用:
@RunWith(MockitoJUnitRunner.class)
@RunWith(JUnitParamsRunner.class)
public class DatabaseModelTest {
// some tests
}
有没有办法在一个测试类中同时使用Mockito和junitpams?您不能这样做,因为根据规范,您不能在同一个带注释的元素上放置同一个注释两次 那么,解决方案是什么?解决方案是只将一个
@RunWith()
放在你无法离开的runner上,然后用其他东西替换另一个。在您的情况下,我想您将删除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();
你可以用任何你想要的跑步者来运行这个测试用例 从JUnit4.7和Mockito 1.10.17开始,这个功能是内置的;有一节课。您可以简单地导入它并添加行
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
您也可以尝试以下方法:
@RunWith(JUnitParamsRunner.class)
public class AbstractTestClass {
// some tests
}
@RunWith(MockitoJUnitRunner.class)
public class DatabaseModelTest extends AbstractTestClass {
// some tests
}
在我的例子中,我试图在SpringBean和
MockitoAnnotations.initMocks(test);
不起作用。相反,您必须在xml文件中定义要使用mock方法构造的bean,如下所示
...
<bean id="classWantedToBeMocked" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.fullpath.ClassWantedToBeMocked" />
</bean>
...
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="file:springconfig.xml")
public class TestClass {
...
@Autowired
private ClassWantedToBeMocked classWantedToBeMocked;
...
when(classWantedToBeMocked.methodWantedToBeMocked()).thenReturn(...);
...
}
此解决方案适用于所有可能的跑步者,而不仅仅是这个mockito示例。例如对于Spring,只需更改runner类并添加必要的注释
@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内部运行。此方法确保在运行静态类TestMockitoJUnitRunner
子运行程序之前正确启动主运行程序,从而有效地使用依赖测试类实现多个嵌套的@RunWith
注释
此外,自PowerMock 1.6发布以来,您可以尽可能轻松地完成这项工作
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(JUnitParamsRunner.class)
public class DatabaseModelTest {
// some tests
}
此处已解释查看此链接
使用这种方法,我将@RunWith(Parameterized.class)-外部运行程序-与@RunWith(MockitoJUnitRunner.class)-内部运行程序组合在一起。我必须添加的唯一调整是将外部类/运行程序中的成员变量设置为静态,以便内部/嵌套运行程序/类可以访问它们。祝你好运,好好享受。我想运行SWTBotJunit4ClassRunner和org.junit.runner.Parameterized同时,我有参数测试,我想在SWT测试失败时截屏(截屏功能由SWTBotJunit4ClassRunner提供)@Becke的回答很好,他首先想走这条路,但这要么是通过争论的诡异。或者在子类中进行参数化,丢失确切测试通过/失败的信息,并且只有最后一个屏幕截图(因为屏幕截图名称从测试本身获得名称)。所以无论哪种方式都有点混乱 在我的例子中,SWTBotJunit4ClassRunner非常简单,因此我克隆了该类的源代码,给它起了我自己的名字参数化ScreenshoRunner,并在原版扩展了TestRunner,我的课程正在扩展参数化的课程,因此本质上我可以使用自己的跑步者,而不是前两个。简而言之,我自己的runner在参数化runner的基础上进行了扩展,同时在其基础上实现了屏幕截图功能,现在我的测试使用了这个“混合”runner,所有测试都可以立即按预期工作(无需更改测试内部的任何内容) 这就是它的样子(为了简洁起见,我从列表中删除了所有注释):
包测试;
导入org.junit.runners.Parameterized;
导入org.eclipse.swtbot.swt.finder.junit.ScreenshotCaptureListener;
导入org.junit.runner.notification.RunListener;
导入org.junit.runner.notification.RunNotifier;
公共类参数化ScreenshoRunner扩展TestRu参数化{
公共参数Screenshotrunner(klass类)可丢弃{
超级(klass);;
}
公共无效运行(运行通知程序通知程序){
RunListener failureSpy=new ScreenshotCaptureListener();
RemovelListener(failureSpy);//删除可以由套件或类运行程序添加的现有侦听器
addListener(failureSpy);
试一试{
super.run(通知程序);
}最后{
通知程序。removeListener(failureSpy);
}
}
}
看一看:这里还有一个很好的例子:这不起作用,只处理子类注释。不起作用-只考虑MockitoJUnitRunner注释检查mockInitialized
是错误的。你想为每一次tetst都制作一个新的模拟品。@BetaRide,这取决于你的需要。有时您希望每次都初始化mock,有时不希望。如果您希望为每个类文件设置一次,可以使用BeforeClass而不是Before,每个测试文件只调用一次。对于Mockito的旧版本(看起来是1.10.5),您必须使用:@Rule public MockitoJUnitRule Mockito=new MockitoJUnitRule(此);代码>MockitoAnnotations.initMocks(this)
创建mock非常慢。最有效的方法是使用@Runwith(MockitoJunitRunner.class),但正如OP所提到的,您不能使用两个@Runwith语句,他需要使用另一个。通过调用JUnitCore.runClasses()
而不检查结果,您就有可能掩盖内部测试中的错误<代码>断言(JUnitCore.runClasses(TestMockitoJUnitRunner.class)。
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);
}
}
}