junit使用
文章目录
- 一 环境依赖
- 二 mock的使用
- 三 静态mock
- 四 spy
- 五 verify
本文不搞junit的深层原理,只谈如何使用。
一 环境依赖
<dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>5.10.2</version><scope>test</scope>
</dependency><dependency><groupId>org.mockito</groupId><artifactId>mockito-junit-jupiter</artifactId><version>5.7.0</version><scope>test</scope>
</dependency>
二 mock的使用
在单元测试中,在单独测试某个组件时,都是使用了挡板技术的,比如测试spring项目的service组件,就会把service调用到的dao设置为挡板。测试时不会去调用真正的dao,这样测试就不会影响到数据库,自然也不会受环境的影响,无论在开发环境还是SIT/UAT环境都可以顺利进行单元测试。下面是我写的例子,首先是我要测试的对象:
public class HelloService {private HelloDao helloDao;public void setHelloDao(HelloDao helloDao) {this.helloDao = helloDao;}public int hello() {return helloDao.query();}
}
注意,我这里没有spring环境.
接下来是我的mock测试代码:
@ExtendWith(MockitoExtension.class)
class HelloServiceTest {@InjectMocksprivate HelloService helloService;@Mockprivate HelloDao helloDao;@Testvoid hello() {Mockito.when(helloDao.query()).thenReturn(3);assertEquals(helloService.hello(),3);}
}
测试通过。
三 静态mock
静态mock需要注意两点:一是要及时关闭,这样不会影响其他测试类。二是只在当前线程有效。
我先写个类:
public class StaticService {public String callStatic() {return HelloUtil.hello();}
}
这个类调用了静态方法。测试的时候可以用静态mock,但是要记得关闭否则运行其他测试类会受到影响:
@ExtendWith(MockitoExtension.class)
class StaticServiceTest {@InjectMocksprivate StaticService staticService;private static MockedStatic<HelloUtil> helloUtil;@Testvoid callStatic() {helloUtil = Mockito.mockStatic(HelloUtil.class);helloUtil.when(()->HelloUtil.hello()).thenReturn("hello");String s = staticService.callStatic();assertEquals(s, "hello");}@AfterAllstatic void close() {helloUtil.close();}
}
再试试多线程:
@Testvoid parallel() throws ExecutionException, InterruptedException {helloUtil = Mockito.mockStatic(HelloUtil.class);helloUtil.when(()->HelloUtil.hello()).thenReturn("hello");String s = staticService.callStatic();assertEquals(s, "hello");FutureTask<String> task = new FutureTask<>(() -> staticService.callStatic());new Thread(task).start();String ret = task.get();assertEquals(ret, "hello");}
测试结果就是失败了。
四 spy
spy是另一种mock技术,用的是new出来的真实对象,但是可以改变部分方法的行为,适合那种部分方法需要mock的场景。我举个例子,这是我需要部分mock的类:
public class SpyDao {public String step1() {return "Hello";}public String step2() {return "world";}
}
测试类的写法上会有点奇怪:
@ExtendWith(MockitoExtension.class)
class SpyServiceTest {@InjectMocksprivate SpyService spyService;@Spyprivate SpyDao spyDao = new SpyDao();@Testvoid call() {Mockito.doReturn("醒过来摸鱼").when(spyDao).step2();assertEquals("Hello, 醒过来摸鱼", spyService.call());}
}
五 verify
verify是验证确实执行了某个方法。比如把上面的dao我加个方法,改成:
public class SpyDao {public String step1() {return "Hello";}public String step2() {return "world";}public String step3() {return "nothing";}
}
其他代码不动,单元测试加上verify机制:
@Testvoid call() {Mockito.doReturn("醒过来摸鱼").when(spyDao).step2();assertEquals("Hello, 醒过来摸鱼", spyService.call());verify(spyDao).step1();verify(spyDao).step3();}
这个单元测试肯定失败,因为没走到step3()这个方法。好了,单元测试就介绍到这了,好久没写博客了。
