通常 Java 中的 Junit 会使用到 mockito 框架,详情可以参考之前专门介绍 Mocktio的博文 .
本文记录 Junit框架下的一些实现方式和解决问题的思路:
@RunWith
Parameterized.class
参数化测试伪代码:
@RunWith(Parameterized.class)
public class ParameterizedTestDemo {
// 初始化 mockito,由于RunWith 已经使用了Parameterized,所以要让 mock 生效可以采用MockitoRule
@Rule
public MockitoRule rule = MockitoJUnit.rule();
@Mock
private StateRepository serviceRepo;
@InjectMock
private StateService service;
// 需要参数化测试的参数
private Integer param;
private EnmuClass state;
// 构造方法,本质是为了每一组参数创建测试类实例
public ParameterizedTestDemo(Integer param, EnmuClass state) {
this.param = param;
this.state = state;
}
// 静态方法,必须返回一个集合。提供测试的具体参数列表,可以在注解中使用 name = {index} 为每组测试提供名称,便于区分
@Parameterized.Parameters(name = "{1}")
public static Collection<Object[]> params() {
return newArrayList(new Object[]{1, EnmuClass.STATE1}, new Object[]{2, EnmuClass.STATE2});
}
@Test
public void testParameterized() {
// given
doReturn(..).when(service).invokeSomeMethod();
// when
service.invokeServiceMethod(param, state);
// then
assertThat(...);
}
}
MockitoJUnitRunner.class
用于初始化 mockito 使@Mock @Spy @InjectMock 等 mockito 注解生效,等价于在 before 方法中调用MockitoAnnotations.openMocks(this);
方法
其他一些常用的第三方 runner: Custom runners
@Rule
用于灵活的增加或重定义每个测试方法的行为。Junit4 内置了一些 rules
ExpectedException:异常测试,类似于@Test(expected = xxxException.class)
public static class HasExpectedException {
@Rule
public final ExpectedException thrown = ExpectedException.none();
@Test
public void throwsNothing() {
}
@Test
public void throwsNullPointerException() {
thrown.expect(NullPointerException.class);
throw new NullPointerException();
}
@Test
public void throwsNullPointerExceptionWithMessage() {
thrown.expect(NullPointerException.class);
thrown.expectMessage("happened?");
thrown.expectMessage(startsWith("What"));
throw new NullPointerException("What happened?");
}
}
ExternalResource:用于在测试前设置了一个外部资源(文件、socket、server、数据库连接等),并保证在测试后将其关闭。
public static class UsesExternalResource {
Server myServer = new Server();
@Rule
public final ExternalResource resource = new ExternalResource() {
@Override
protected void before() throws Throwable {
myServer.connect();
};
@Override
protected void after() {
myServer.disconnect();
};
};
@Test
public void testFoo() {
new Client().run(myServer);
}
}
TemporaryFolder:用于创建文件与目录并且在测试运行结束后将其删除。
public static class HasTempFolder {
@Rule
public final TemporaryFolder folder = new TemporaryFolder();
@Test
public void testUsingTempFolder() throws IOException {
File createdFile = folder.newFile("myfile.txt");
File createdFolder = folder.newFolder("subfolder");
// ...
}
}
TestName:在测试中获取当前测试方法的名称。
public class NameRuleTest {
@Rule
public final TestName name = new TestName();
@Test
public void testA() {
assertEquals("testA", name.getMethodName());
}
@Test
public void testB() {
assertEquals("testB", name.getMethodName());
}
}
TestWatcher:提供五个触发点:测试开始、测试完成、测试成功、测试跳过、测试失败,允许我们在每个触发点执行自定义的逻辑。 例如如下在每个触发点连续记录 log
public class WatchmanTest {
private static String watchedLog;
@Rule
public final TestRule watchman = new TestWatcher() {
@Override
public Statement apply(Statement base, Description description) {
return super.apply(base, description);
}
@Override
protected void succeeded(Description description) {
watchedLog += description.getDisplayName() + " " + "success!\n";
}
@Override
protected void failed(Throwable e, Description description) {
watchedLog += description.getDisplayName() + " " + e.getClass().getSimpleName() + "\n";
}
@Override
protected void skipped(AssumptionViolatedException e, Description description) {
watchedLog += description.getDisplayName() + " " + e.getClass().getSimpleName() + "\n";
}
@Override
protected void starting(Description description) {
super.starting(description);
}
@Override
protected void finished(Description description) {
super.finished(description);
}
};
@Test
public void fails() {
fail();
}
@Test
public void succeeds() {
}
}
Timeout:支持为测试类中的所有测试方法设置相同的超时时间,类似于@Test(timeout = 100)
除此以为,还有第三方 rule 实现或者自己实现 TestRule,MethodRule接口
例如 MockitoRule 用来初始化 mockito
网友评论