当前位置:   article > 正文

Java单元测试打桩-mockito,PowerMockito简单使用,模拟方法内new对象_mockito new撖寡情

mockito new撖寡情

0、需要的jar

  1. <dependency>
  2. <groupId>junit</groupId>
  3. <artifactId>junit</artifactId>
  4. <version>4.12</version>
  5. <scope>test</scope>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.mockito</groupId>
  9. <artifactId>mockito-all</artifactId>
  10. <version>2.0.2-beta</version>
  11. <scope>test</scope>
  12. </dependency>
  13. <dependency>
  14. <groupId>org.powermock</groupId>
  15. <artifactId>powermock-module-junit4</artifactId>
  16. <version>1.7.4</version>
  17. <scope>test</scope>
  18. </dependency>
  19. <dependency>
  20. <groupId>org.powermock</groupId>
  21. <artifactId>powermock-api-mockito</artifactId>
  22. <version>1.7.4</version>
  23. <scope>test</scope>
  24. </dependency>

1、简单单元测试

  1. package test;
  2. public class ProcessDB {
  3. public String getResultOfConnectDB() {
  4. return "haha, Really went to the database";
  5. }
  6. }
  1. package test;
  2. public class BussinessService {
  3. private ProcessDB processDB;
  4. public BussinessService(ProcessDB db){
  5. this.processDB = db;
  6. }
  7. public String testedMehtod(){
  8. return processDB.getResultOfConnectDB();
  9. }
  10. }

测试类

  1. package test
  2. import org.junit.Assert;
  3. import org.junit.Test;
  4. public class BussinessTest {
  5. @Test
  6. public void testFuction(){
  7. ProcessDB db = new ProcessDB();
  8. BussinessService bs = new BussinessService(db);
  9. System.out.println(bs.testedMehtod());
  10. Assert.assertEquals("haha, Really went to the database", bs.testedMehtod());
  11. }
  12. }

正常的一个单元测试,测试一下正常流程,对结果进行断言。

2、mockito模拟对象

大多数时候,所测试对象依赖于一些例如数据库连接,中间件等其他远程服务,对测试造成了影响,下面用mockito模拟连接数据库的过程

  1. import static org.junit.Assert.*;
  2. import org.junit.Before;
  3. import org.junit.Test;
  4. public class BussinessTest {
  5. private ProcessDB mockDB;
  6. private BussinessService bs;
  7. @Before
  8. public void setUp() throws Exception {
  9. mockDB = mock(ProcessDB.class);
  10. String aa = "haha, everything is fake";
  11. when(mockDB.getResultOfConnectDB()).thenReturn(aa);
  12. bs = new BussinessService(mockDB);
  13. }
  14. @Test
  15. public void mockConnectDB(){
  16. assertEquals("haha, everything is fake", bs.testedMehtod());
  17. }
  18. }

这样就模拟了连接数据库的过程输出,本来真实连接数据库的时候输出“haha, Really went to the database“,但是真实连接数据库来测试比较麻烦,所以现在被模拟对象取代,输出你自己造的数据"haha, everything is fake"。

不过这一切都建立在你mock的对象是你被测试对象的属性变量,而不是在测试方法内部自己new出来的ProcessDB对象。下面看方法内部new对象,使用mockito模拟对象会怎样

3、mockito模拟方法内部new的对象

被测试类简单修改:

  1. package test;
  2. public class BussinessService {
  3. public String testedMehtod(){
  4. ProcessDB processDB = new ProcessDB();
  5. return processDB.getResultOfConnectDB();
  6. }
  7. }

测试:

  1. package test;
  2. import static org.mockito.Mockito.mock;
  3. import static org.mockito.Mockito.when;
  4. import static org.junit.Assert.*;
  5. import org.junit.Before;
  6. import org.junit.Test;
  7. public class BussinessTest {
  8. private ProcessDB mockDB;
  9. private BussinessService bs;
  10. @Before
  11. public void setUp() throws Exception {
  12. mockDB = mock(ProcessDB.class);
  13. String aa = "haha, everything is fake";
  14. when(mockDB.getResultOfConnectDB()).thenReturn(aa);
  15. bs = new BussinessService();
  16. }
  17. @Test
  18. public void mockConnectDB(){
  19. System.out.println(bs.testedMehtod());
  20. assertEquals("haha, everything is fake", bs.testedMehtod());
  21. }
  22. }

测试失败:


4、PowerMockito模拟方法内部创建出来的对象

  1. package test;
  2. public class ProcessDB {
  3. public static ProcessDB getInstance(){
  4. return new ProcessDB();
  5. }
  6. public String getResultOfConnectDB() {
  7. return "haha, Really went to the database";
  8. }
  9. }
  1. package test;
  2. public class BussinessService {
  3. public String testedMehtod(){
  4. ProcessDB processDB = ProcessDB.getInstance();
  5. return processDB.getResultOfConnectDB();
  6. }
  7. }

有时候被测试类存在这样的写法,上述mockito又不管用,使用PowerMockito来模拟

  1. package test;
  2. import static org.junit.Assert.assertEquals;
  3. import org.junit.Test;
  4. import org.junit.runner.RunWith;
  5. import org.powermock.api.mockito.PowerMockito;
  6. import org.powermock.core.classloader.annotations.PrepareForTest;
  7. import org.powermock.modules.junit4.PowerMockRunner;
  8. @RunWith(PowerMockRunner.class)
  9. @PrepareForTest(ProcessDB.class)
  10. public class BussinessTest {
  11. private ProcessDB mockDB;
  12. private BussinessService bs;
  13. @Test
  14. public void mockConnectDB(){
  15. PowerMockito.mockStatic(ProcessDB.class);
  16. mockDB = PowerMockito.mock(ProcessDB.class);
  17. bs = new BussinessService();
  18. PowerMockito.when(ProcessDB.getInstance()).thenReturn(mockDB);
  19. String aa = "haha, everything is fake";
  20. PowerMockito.when(mockDB.getResultOfConnectDB()).thenReturn(aa);
  21. System.out.println(bs.testedMehtod());
  22. assertEquals("haha, everything is fake", bs.testedMehtod());
  23. }
  24. }

这样又可以测试通过,模拟了连接数据库的过程,特别注意头顶的两个注解,@RunWith(PowerMockRunner.class)  

@PrepareForTest(ProcessDB.class) 。分两步:第一步模拟出假对象PowerMockito.when(ProcessDB.getInstance()).thenReturn(mockDB); ,第二步模拟假对象调用的方法PowerMockito.when(mockDB.getResultOfConnectDB()).thenReturn(aa);

5、仿照上面解决3中的问题,内部直接使用new对象而不是通过静态方法getInstance()

  1. package test;
  2. public class BussinessService {
  3. public String testedMehtod(){
  4. ProcessDB processDB = new ProcessDB();
  5. return processDB.getResultOfConnectDB();
  6. }
  7. }
测试类:
  1. package test;
  2. import static org.junit.Assert.assertEquals;
  3. import org.junit.Test;
  4. import org.junit.runner.RunWith;
  5. import org.powermock.api.mockito.PowerMockito;
  6. import org.powermock.core.classloader.annotations.PrepareForTest;
  7. import org.powermock.modules.junit4.PowerMockRunner;
  8. @RunWith(PowerMockRunner.class)
  9. @PrepareForTest(ProcessDB.class)
  10. public class BussinessTest {
  11. private ProcessDB mockDB;
  12. private BussinessService bs;
  13. @Test
  14. public void mockConnectDB(){
  15. mockDB = PowerMockito.mock(ProcessDB.class);
  16. bs = new BussinessService();
  17. try {
  18. PowerMockito.whenNew(ProcessDB.class).withNoArguments().thenReturn(mockDB);
  19. } catch (Exception e) {
  20. e.printStackTrace();
  21. }
  22. String aa = "haha, everything is fake";
  23. PowerMockito.when(mockDB.getResultOfConnectDB()).thenReturn(aa);
  24. System.out.println(bs.testedMehtod());
  25. assertEquals("haha, everything is fake", bs.testedMehtod());
  26. }
  27. }

这样看似与4相似,但是结果测试又通不过,输出的又是"haha, Really went to the database",加上PowerMockito.mockStatic(ProcessDB.class)也不管用。

6、真正解决3中的new对象的问题

其实5已经基本上实现了,经过一段时间的排查,原来问题是出在头顶上的两个注解上

  1. package test;
  2. import static org.junit.Assert.assertEquals;
  3. import org.junit.Test;
  4. import org.junit.runner.RunWith;
  5. import org.powermock.api.mockito.PowerMockito;
  6. import org.powermock.core.classloader.annotations.PrepareForTest;
  7. import org.powermock.modules.junit4.PowerMockRunner;
  8. @RunWith(PowerMockRunner.class)
  9. @PrepareForTest({ProcessDB.class, BussinessService.class})
  10. public class BussinessTest {
  11. private ProcessDB mockDB;
  12. private BussinessService bs;
  13. @Test
  14. public void mockConnectDB(){
  15. mockDB = PowerMockito.mock(ProcessDB.class);
  16. bs = new BussinessService();
  17. try {
  18. PowerMockito.whenNew(ProcessDB.class).withNoArguments().thenReturn(mockDB);
  19. } catch (Exception e) {
  20. e.printStackTrace();
  21. }
  22. String aa = "haha, everything is fake";
  23. PowerMockito.when(mockDB.getResultOfConnectDB()).thenReturn(aa);
  24. System.out.println(bs.testedMehtod());
  25. assertEquals("haha, everything is fake", bs.testedMehtod());
  26. }
  27. }

测试通过,一切OK

这样应该可以实现模拟对象的各种情况了,即使代码不规范,喜欢到处new依赖对象而不是将依赖对象注入服务,也可以轻松模拟对象,模拟连接远程服务,构造自己想要的数据从而完成测试自己代码逻辑。

7、流程测试的最后一步是外部依赖时的验证(例如发送到kafka等)

  1. package mockito;
  2. import java.util.LinkedList;
  3. public class Verify {
  4. private LinkedList k ;
  5. public Verify(LinkedList k){
  6. this.k = k;
  7. }
  8. public void test(){
  9. k.add("d");
  10. k.add("b");
  11. System.out.println(k.get(0));
  12. }
  13. }
  1. package mockito;
  2. import java.util.LinkedList;
  3. import static org.mockito.Mockito.*;
  4. import org.junit.Test;
  5. public class VeriryTestTest {
  6. @Test
  7. public void testt(){
  8. LinkedList mockedList = mock(LinkedList.class);
  9. when(mockedList.get(anyInt())).thenReturn("first");
  10. new Verify(mockedList).test();
  11. verify(mockedList).get(anyInt());
  12. }
  13. }
此测试LinkedList相当于外部依赖,最后验证依赖的某个方法是否被调用过,如果有机会调用说明流程上基本上没什么问题,验证不严谨。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/274420
推荐阅读
相关标签
  

闽ICP备14008679号