我编写单元测试并想在一个测试类中使用JUnitParamsRunner
和MockitoJUnitRunner
。
不幸的是,以下方法不能正常工作:
@RunWith(MockitoJUnitRunner.class)
@RunWith(JUnitParamsRunner.class)
public class DatabaseModelTest {
// some tests
}
有没有办法在一个测试类中同时使用Mockito和JUnitParams?
我编写单元测试并想在一个测试类中使用JUnitParamsRunner
和MockitoJUnitRunner
。
不幸的是,以下方法不能正常工作:
@RunWith(MockitoJUnitRunner.class)
@RunWith(JUnitParamsRunner.class)
public class DatabaseModelTest {
// some tests
}
有没有办法在一个测试类中同时使用Mockito和JUnitParams?
你不能这样做,因为根据规范,你不能在同一个注释元素上放置相同的注释两次。
那么,有什么解决办法吗?答案是只使用一个带有你不能没有的运行器@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;
}
}
然而,更好、可重复使用的解决方案可以通过JUnit规则实现。
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从JUnit 4.7和Mockito 1.10.17开始,这个功能已经内置;有一个org.mockito.junit.MockitoRule
类。您可以简单地导入它并添加此行
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
到你的测试类。
@Rule public MockitoJUnitRule mockito = new MockitoJUnitRule(this);
- Cliff SunMockitoAnnotations.initMocks(this)
创建模拟对象的速度非常慢。最高效的方法是使用 @RunWith(MockitoJUnitRunner.class)
。 - ant2009这个解决方案适用于所有可能的运行器,而不仅仅是这个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
依赖于它(按逻辑),并且它将在@Test
方法中的主要内容内部运行,同时调用JUnitCore.runClasses(TestMockitoJUnitRunner.class)
。此方法确保在static class TestMockitoJUnitRunner
子运行程序运行之前正确启动主运行程序,有效地实现了具有依赖测试类的多个嵌套@RunWith
注释。
还可以访问https://bekce.github.io/junit-multiple-runwith-dependent-tests
JUnitCore.runClasses()
,则有可能掩盖内部测试中的错误。assert(JUnitCore.runClasses(TestMockitoJUnitRunner.class).wasSuccessful());
至少会向您报告错误。 - Robotnik@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(JUnitParamsRunner.class)
public class DatabaseModelTest {
// some tests
}
这里解释了如何使用另一个JUnit Runner来配合PowerMock。具体内容请看https://blog.jayway.com/2014/11/29/using-another-junit-runner-with-powermock/
在我的情况下,我正在尝试Mock Spring Bean中的一些方法。
MockitoAnnotations.initMocks(test);
...
<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(...);
...
}
@ExtendWith(MockitoExtension.class)
@ExtendWith(AnotherExtension.class)
public class MyTest {
// some tests
}
JUnitParams
框架已内置于JUnit 5中。看看这个链接 https://bekce.github.io/junit-multiple-runwith-dependent-tests/,使用这种方法,我将 @RunWith(Parameterized.class) - 外部 runner - 与 @RunWith(MockitoJUnitRunner.class) - 内部 runner - 结合起来。唯一需要添加的调整是使外部类/runner 中的成员变量静态化,以便让内部/嵌套 runner/class 可以访问它们。祝好运并享受。
我想同时运行SWTBotJunit4ClassRunner和org.junit.runners.Parameterized,我有参数化测试,并且在SWT测试失败时想要截屏(截屏功能由SWTBotJunit4ClassRunner提供)。@bekce的答案很好,一开始想走这条路,但是通过参数传递有点古怪。或者在子类中执行参数化并且失去了确切测试通过/失败的信息,只有最后一个截图(因为截图名称从测试本身获取)。所以无论哪种方式都有点混乱。
在我的情况下,SWTBotJunit4ClassRunner足够简单,因此我克隆了该类的源代码,给它起了自己的名字ParametrizedScreenshotRunner,原来的类扩展了TestRunner,而我的类则扩展了Parameterized类,因此实质上我可以使用自己的运行器代替前两个。简而言之,我的运行器在Parameterized运行器的基础上实现了截图功能,现在我的测试使用这个“混合”运行器,所有测试立即按预期工作(不需要更改测试内部的任何内容)。
这就是它的外观(为了简洁起见,我从列表中删除了所有注释):
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);
}
}
}
你也可以尝试这个:
@RunWith(JUnitParamsRunner.class)
public class AbstractTestClass {
// some tests
}
@RunWith(MockitoJUnitRunner.class)
public class DatabaseModelTest extends AbstractTestClass {
// some tests
}