范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

SpringBoot单元测试详解(MockitoMockBean)

  一个测试方法主要包括三部分:
  1)setup
  2)执行操作
  3)验证结果public class CalculatorTest {     Calculator mCalculator;      @Before      public void setup() {         mCalculator = new Calculator();     }      @Test      public void testAdd() throws Exception {         int sum = mCalculator.add(1, 2);         assertEquals(3, sum);       }      @Test     @Ignore("not implemented yet")      public void testMultiply() throws Exception {     }           @Test(expected = IllegalArgumentException.class)     public void test() {         mCalculator.pide(4, 0);     } } Junit 基本注解介绍@BeforeClass 在所有测试方法执行前执行一次,一般在其中写上整体初始化的代码。@AfterClass 在所有测试方法后执行一次,一般在其中写上销毁和释放资源的代码。 @BeforeClass public static void test(){      } @AfterClass public static void test(){ } @Before 在每个方法测试前执行,一般用来初始化方法(比如我们在测试别的方法时,类中与其他测试方法共享的值已经被改变,为了保证测试结果的有效性,我们会在@Before注解的方法中重置数据)@After 在每个测试方法执行后,在方法执行完成后要做的事情。@Test(timeout = 1000) 测试方法执行超过1000毫秒后算超时,测试将失败。@Test(expected = Exception.class) 测试方法期望得到的异常类,如果方法执行没有抛出指定的异常,则测试失败。@Ignore("not ready yet") 执行测试时将忽略掉此方法,如果用于修饰类,则忽略整个类。@Test 编写一般测试用例用。@RunWith 在 Junit 中有很多个 Runner,他们负责调用你的测试代码,每一个 Runner 都有各自的特殊功能,你根据需要选择不同的 Runner 来运行你的测试代码。
  如果我们只是简单的做普通 Java 测试,不涉及 Spring Web 项目,你可以省略 @RunWith 注解,你要根据需要选择不同的 Runner 来运行你的测试代码。测试方法执行顺序
  按照设计,Junit不指定test方法的执行顺序。@FixMethodOrder(MethodSorters.JVM):保留测试方法的执行顺序为JVM返回的顺序。每次测试的执行顺序有可能会所不同。@FixMethodOrder(MethodSorters.NAME_ASCENDING) :根据测试方法的方法名排序,按照词典排序规则(ASC,从小到大,递增)。
  Failure 是测试失败,Error 是程序出错。测试方法命名约定
  Maven本身并不是一个单元测试框架,它只是在构建执行到特定生命周期阶段的时候,通过插件来执行JUnit或者TestNG的测试用例。这个插件就是maven-surefire-plugin,也可以称为测试运行器(Test Runner),它能兼容JUnit 3、JUnit 4以及TestNG。
  在默认情况下,maven-surefire-plugin的test目标会自动执行测试源码路径(默认为src/test/java/)下所有符合一组命名模式的测试类。这组模式为:*/Test.java:任何子目录下所有命名以Test开关的Java类。*/Test.java:任何子目录下所有命名以Test结尾的Java类。*/TestCase.java:任何子目录下所有命名以TestCase结尾的Java类。基于 Spring 的单元测试编写
  首先我们项目一般都是 MVC 分层的,而单元测试主要是在 Dao 层和 Service 层上进行编写。从项目结构上来说,Service 层是依赖 Dao 层的,但是从单元测试角度,对某个 Service 进行单元的时候,他所有依赖的类都应该进行Mock。而 Dao 层单元测试就比较简单了,只依赖数据库中的数据。Mockito
  Mockito是mocking框架,它让你用简洁的API做测试。而且Mockito简单易学,它可读性强和验证语法简洁。
  Mockito 是一个针对 Java 的单元测试模拟框架,它与 EasyMock 和 jMock 很相似,都是为了简化单元测试过程中测试上下文 ( 或者称之为测试驱动函数以及桩函数 ) 的搭建而开发的工具
  相对于 EasyMock 和 jMock,Mockito 的优点是通过在执行后校验哪些函数已经被调用,消除了对期望行为(expectations)的需要。其它的 mocking 库需要在执行前记录期望行为(expectations),而这导致了丑陋的初始化代码。
  SpringBoot 中的 pom.xml 文件需要添加的依赖:             org.springframework.boot         spring-boot-starter-test         test     
  进入 spring-boot-starter-test-2.1.3.RELEASE.pom 可以看到该依赖中已经有单元测试所需的大部分依赖,如:junitmockitohamcrest
  若为其他 spring 项目,需要自己添加 Junit 和 mockito 项目。常用的 Mockito 方法:
  方法名
  描述
  Mockito.mock(classToMock)
  模拟对象
  Mockito.verify(mock)
  验证行为是否发生
  Mockito.when(methodCall).thenReturn(value1).thenReturn(value2)
  触发时第一次返回value1,第n次都返回value2
  Mockito.doThrow(toBeThrown).when(mock).[method]
  模拟抛出异常。
  Mockito.mock(classToMock,defaultAnswer)
  使用默认Answer模拟对象
  Mockito.when(methodCall).thenReturn(value)
  参数匹配
  Mockito.doReturn(toBeReturned).when(mock).[method]
  参数匹配(直接执行不判断)
  Mockito.when(methodCall).thenAnswer(answer))
  预期回调接口生成期望值
  Mockito.doAnswer(answer).when(methodCall).[method]
  预期回调接口生成期望值(直接执行不判断)
  Mockito.spy(Object)
  用spy监控真实对象,设置真实对象行为
  Mockito.doNothing().when(mock).[method]
  不做任何返回
  Mockito.doCallRealMethod().when(mock).[method] //等价于Mockito.when(mock.[method]).thenCallRealMethod();
  调用真实的方法
  reset(mock)
  重置mock示例:验证行为是否发生 List mock =  Mockito.mock(List.class);  mock.add(1); mock.clear();  Mockito.verify(mock).add(1); Mockito.verify(mock).clear(); 多次触发返回不同值 Iterator iterator = mock(Iterator.class);  Mockito.when(iterator.next()).thenReturn("hello").thenReturn("world");  String result = iterator.next() + " " + iterator.next() + " " + iterator.next();  Assert.assertEquals("hello world world",result); 模拟抛出异常@Test(expected = IOException.class) public void when_thenThrow() throws IOException{       OutputStream mock = Mockito.mock(OutputStream.class);              Mockito.doThrow(new IOException()).when(mock).close();       mock.close();   } 使用默认Answer模拟对象
  RETURNS_DEEP_STUBS 是创建mock对象时的备选参数之一
  以下方法deepstubsTest和deepstubsTest2是等价的  @Test   public void deepstubsTest(){       A a=Mockito.mock(A.class,Mockito.RETURNS_DEEP_STUBS);       Mockito.when(a.getB().getName()).thenReturn("Beijing");       Assert.assertEquals("Beijing",a.getB().getName());   }    @Test   public void deepstubsTest2(){       A a=Mockito.mock(A.class);       B b=Mockito.mock(B.class);       Mockito.when(a.getB()).thenReturn(b);       Mockito.when(b.getName()).thenReturn("Beijing");       Assert.assertEquals("Beijing",a.getB().getName());   }   class A{       private B b;       public B getB(){           return b;       }       public void setB(B b){           this.b=b;       }   }   class B{       private String name;       public String getName(){           return name;       }       public void setName(String name){           this.name = name;       }       public String getSex(Integer sex){           if(sex==1){               return "man";           }else{               return "woman";           }       }   } 参数匹配@Test public void with_arguments(){     B b = Mockito.mock(B.class);          Mockito.when(b.getSex(1)).thenReturn("男");     Mockito.when(b.getSex(2)).thenReturn("女");     Assert.assertEquals("男", b.getSex(1));     Assert.assertEquals("女", b.getSex(2));          Assert.assertEquals(null, b.getSex(0)); } class B{     private String name;     public String getName(){         return name;     }     public void setName(String name){         this.name = name;     }     public String getSex(Integer sex){         if(sex==1){             return "man";         }else{             return "woman";         }     } } 匹配任意参数
  Mockito.anyInt() 任何 int 值 ;
  Mockito.anyLong() 任何 long 值 ;
  Mockito.anyString() 任何 String 值 ;
  Mockito.any(XXX.class) 任何 XXX 类型的值 等等。@Test public void with_unspecified_arguments(){     List list = Mockito.mock(List.class);          Mockito.when(list.get(Mockito.anyInt())).thenReturn(1);     Mockito.when(list.contains(Mockito.argThat(new IsValid()))).thenReturn(true);     Assert.assertEquals(1,list.get(1));     Assert.assertEquals(1,list.get(999));     Assert.assertTrue(list.contains(1));     Assert.assertTrue(!list.contains(3)); } class IsValid extends ArgumentMatcher{     @Override     public boolean matches(Object obj) {         return obj.equals(1) || obj.equals(2);     } }
  注意:使用了参数匹配,那么所有的参数都必须通过matchers来匹配
  Mockito继承Matchers,anyInt()等均为Matchers方法
  当传入两个参数,其中一个参数采用任意参数时,指定参数需要matchers来对比Comparator comparator = mock(Comparator.class); comparator.compare("nihao","hello");  Mockito.verify(comparator).compare(Mockito.anyString(),Mockito.eq("hello"));   自定义参数匹配@Test public void argumentMatchersTest(){        List mock = mock(List.class);        Mockito.when(mock.addAll(Mockito.argThat(new IsListofTwoElements()))).thenReturn(true);    Assert.assertTrue(mock.addAll(Arrays.asList("one","two","three"))); }  class IsListofTwoElements extends ArgumentMatcher {    public boolean matches(Object list)    {        return((List)list).size()==3;    } } 预期回调接口生成期望值@Test public void answerTest(){       List mockList = Mockito.mock(List.class);              Mockito.when(mockList.get(Mockito.anyInt())).thenAnswer(new CustomAnswer());       Assert.assertEquals("hello world:0",mockList.get(0));       Assert.assertEquals("hello world:999",mockList.get(999));   }   private class CustomAnswer implements Answer {       @Override       public String answer(InvocationOnMock invocation) throws Throwable {           Object[] args = invocation.getArguments();           return "hello world:"+args[0];       }   } 等价于:(也可使用匿名内部类实现) @Test  public void answer_with_callback(){              Mockito.when(mockList.get(Mockito.anyInt())).thenAnswer(new Answer() {           @Override           public Object answer(InvocationOnMock invocation) throws Throwable {               Object[] args = invocation.getArguments();               return "hello world:"+args[0];           }       });       Assert.assertEquals("hello world:0",mockList.get(0));      Assert. assertEquals("hello world:999",mockList.get(999));   } 预期回调接口生成期望值(直接执行)@Test public void testAnswer1(){ List mock = Mockito.mock(List.class);         Mockito.doAnswer(new CustomAnswer()).when(mock).get(Mockito.anyInt());         Assert.assertEquals("大于三", mock.get(4));       Assert.assertEquals("小于三", mock.get(2)); } public class CustomAnswer implements Answer {     public String answer(InvocationOnMock invocation) throws Throwable {         Object[] args = invocation.getArguments();         Integer num = (Integer)args[0];         if( num>3 ){             return "大于三";         } else {             return "小于三";          }     } } 修改对未预设的调用返回默认期望(指定返回值) List mock = Mockito.mock(List.class,new Answer() {      @Override      public Object answer(InvocationOnMock invocation) throws Throwable {          return 999;      }  });    Assert.assertEquals(999, mock.get(1));    Assert.assertEquals(999,mock.size()); 用spy监控真实对象,设置真实对象行为    @Test(expected = IndexOutOfBoundsException.class)     public void spy_on_real_objects(){         List list = new LinkedList();         List spy = Mockito.spy(list);                                     Mockito.doReturn(999).when(spy).get(999);                  Mockito.when(spy.size()).thenReturn(100);                  spy.add(1);         spy.add(2);         Assert.assertEquals(100,spy.size());         Assert.assertEquals(1,spy.get(0));         Assert.assertEquals(2,spy.get(1));         Assert.assertEquals(999,spy.get(999));     } 不做任何返回@Test public void Test() {     A a = Mockito.mock(A.class);          Mockito.doNothing().when(a).setName(Mockito.anyString());     a.setName("bb");     Assert.assertEquals("bb",a.getName()); } class A {     private String name;     private void setName(String name){         this.name = name;     }     private String getName(){         return name;     } } 调用真实的方法@Test public void Test() {     A a = Mockito.mock(A.class);          Mockito.when(a.getName()).thenReturn("bb");     Assert.assertEquals("bb",a.getName());          Mockito.doCallRealMethod().when(a).getName();     Assert.assertEquals("zhangsan",a.getName()); } class A {     public String getName(){         return "zhangsan";     } } 重置 mock    @Test     public void reset_mock(){         List list = mock(List.class);         Mockito. when(list.size()).thenReturn(10);         list.add(1);         Assert.assertEquals(10,list.size());                  Mockito.reset(list);         Assert.assertEquals(0,list.size());     } @Mock 注解public class MockitoTest {     @Mock     private List mockList;          public MockitoTest(){         MockitoAnnotations.initMocks(this);     }     @Test     public void AnnoTest() {             mockList.add(1);         Mockito.verify(mockList).add(1);     } } 指定测试类使用运行器:MockitoJUnitRunner@RunWith(MockitoJUnitRunner.class) public class MockitoTest2 {     @Mock     private List mockList;      @Test     public void shorthand(){         mockList.add(1);         Mockito.verify(mockList).add(1);     } } @MockBean
  使用 @MockBean 可以解决单元测试中的一些依赖问题,示例如下:@RunWith(SpringRunner.class) @SpringBootTest public class ServiceWithMockBeanTest {     @MockBean     SampleDependencyA dependencyA;     @Autowired     SampleService sampleService;      @Test     public void testDependency() {         when(dependencyA.getExternalValue(anyString())).thenReturn("mock val: A");         assertEquals("mock val: A", sampleService.foo());     } }
  @MockBean 只能 mock 本地的代码——或者说是自己写的代码,对于储存在库中而且又是以 Bean 的形式装配到代码中的类无能为力。
  @SpyBean 解决了 SpringBoot 的单元测试中 @MockBean 不能 mock 库中自动装配的 Bean 的局限(目前还没需求,有需要的自己查阅资料)。
  参考:
  https://www.cnblogs.com/Ming8006/p/6297333.html#c3
  https://www.vogella.com/tutorials/Mockito/article.html
十四五新型基础设施建设专家谈之三积极打造网络化智能化服务化协同化的融合基础设施体系融合基础设施是新型基础设施的重要组成部分,主要是指深度应用互联网大数据人工智能等技术,支撑传统基础设施转型升级,进而形成的一类新型基础设施。融合基础设施范围广阔,涉及到所有传统基础Java锁机制了解一下在多线程环境下,程序往往会出现一些线程安全问题,为此,Java提供了一些线程的同步机制来解决安全问题,比如synchronized锁和Lock锁都能解决线程安全问题。悲观锁和乐观锁如果当年倪光南成了联想老板,现在中国的芯片会怎么样?如果让倪光南院士继续执掌联想,在当时中国与国外芯片技术差距不太大的情况下,即便不是超过,也不可能像现在这样差距差的这么大,柳教父不是一个技术型的人,同任正非,曹德旺这些有着战略眼光生命的生与死的区别是什么?理论上刚溺水死亡的人身上什么也没缺,缺氧的话输送氧气就能救活吗?大脑死亡人就是死了,心脏不跳了大脑没有血液神经就都停止运行人就死亡了,计算机拔了电源,尽管CPU内存硬盘,包括操作系统都是完好无损的,但是它就是不能工作!遗憾的是计算机哪怕停电10两张卡在同一部手机,可以开两个微信吗?看到这个问题我就想乐,我父亲和题主在微信双开上也问过我这个问题。我说不用两张卡在一起也可以一台手机上开两个微信,他不信,我当时解释半天并帮他登陆微信他这才信,下面我说一下当时我父亲怎么把微信删除的聊天记录恢复到手机上?查看微信聊天记录对较多数的人还是比较厌烦的,毕竟会感觉自己的隐私被人知道,或者查看别人的隐私是不好的行为。然而还是有一些人需要查看聊天记录详细内容的,因为有些聊天记录信息需要去查看骁龙660和骁龙660AIE有什么区别?谢谢邀请!从今年3月开始,国产手机厂商新机井喷式发布,在这波新机中,OPPOR15梦镜版vivoX21以及小米6X等诸多产品都搭载了高通骁龙660AIESoC。对于许多人来说,高通三种方法实现调用Restful接口1基本介绍Restful接口的调用,前端一般使用ajax调用,后端可以使用的方法比较多,本次介绍三种1)HttpURLConnection实现2)HttpClient实现3)SprGo语言学习笔记Go语言特征静态强类型编译型并发型并具有垃圾回收功能的编程语言用Goroutine运行所有的一切,包括main。main入口函数,是一种虚拟线程。Go语言运行时会参与调度gorouXenobot3。0来了!首个可自我繁殖活体机器人问世文AndreaMorrisXenobot是世界上第一个由人工智能设计的生物机器人,可以自我修复和自我复制。1948年,匈牙利裔美国数学家约翰冯诺伊曼(JohnvonNeumann)噩耗再次传来,滴滴只能自保,网约车司机挺住网约车突然进入下半场,各家平台喜提空白期,纷纷高调争抢市场。首汽约车曹操出行一喂顺风车等平台你追我赶,这样下去,格局或将迎来新变化。眼见行业竞争日渐激烈,其实真正的较量才刚刚开始一
北京X7和哈弗H6比,谁才是你的心仪之选?北京汽车在市场上的知名度还是挺高的,它新推出的车型很快也人尽皆知了,首款车型就是北京X7,站在一个旁观者的角度说,该车最大的亮点就是它的设计,其画风给我的第一眼印象,跟现在的新势力在鹭岛缘定520!燕之屋首届集体婚礼成功举办跑车护航应援接亲总裁证婚5月20日下午,厦门燕之屋首届集体婚礼在海悦山庄酒店盛大开启,9对新人在领导同事亲友的见证下牵手同行,结为连理。图厦门燕之屋首届集体婚礼现场图厦门燕之屋首届东风风行T5EVO,一部让年轻人欲罢不能的全新SUV现在国产车可是设计的越来越漂亮了,这部T5evo第一眼看到之后就感觉可能是挖来的设计师,这么说可能有些不妥,但这几年国产车的成长是有目共睹的,尤其在质量稳定方面做的相当不错,加上厚恒洁作为卫浴行业唯一代表受邀参加2021AWE近期,2021AWE(中国家电及消费电子博览会)在上海虹桥国家会展中心成功。今年AWE首次扩充了智能卫浴品类,恒洁作为卫浴行业唯一代表,同时也是AWE十年来首个受邀参展的专业卫浴品社群营销成功运营社群5要素之复制作者小蚱蜢简介8年互联网营销实战经验,乐于为大家分享实战经验。寻找互联网营销同行交流经验提升自我。精力有限,不卖课程,不付费学习,单纯以互联网交流为主,所有文章纯属本人实战及见解,社群运营这就是社群带给你的10个价值点作者小蚱蜢简介8年互联网营销实战经验,乐于为大家分享实战经验。寻找互联网营销同行交流经验提升自我。精力有限,不卖课程,不付费学习,单纯以互联网交流为主,所有文章纯属本人实战及见解,社群营销成功运营社群5要素之结构作者小蚱蜢简介8年互联网营销实战经验,乐于为大家分享实战经验。寻找互联网营销同行交流经验提升自我。精力有限,不卖课程,不付费学习,单纯以互联网交流为主,所有文章纯属本人实战及见解,社群运营了解社群营销的9大人性法则作者小蚱蜢简介8年互联网营销实战经验,乐于为大家分享实战经验。寻找互联网营销同行交流经验提升自我。精力有限,不卖课程,不付费学习,单纯以互联网交流为主,所有文章纯属本人实战及见解,社群营销成功运营社群5要素之输出作者小蚱蜢简介8年互联网营销实战经验,乐于为大家分享实战经验。寻找互联网营销同行交流经验提升自我。精力有限,不卖课程,不付费学习,单纯以互联网交流为主,所有文章纯属本人实战及见解,如何将一个产品打造成爆品,只需要掌握以下两点,你知道吗?一个产品想要做成爆品,前提条件毋容置疑是需要产品本身质量款式等要硬。其次才是营销,当然小蚱蜢不否认有些人利用强大的营销手段把一个产品打造一个爆品,如质量不过关,那么该爆品的寿命却很社群营销你的社群是不是很多都是僵尸群呢?昨天说到做社群是要改变社群思维,然而有个朋友说我的群很多,但都是一开始火热,过一段时间就每人说话了,一说话可能都是在打广告,比如砍价,点赞等等。相信许多人的微信群多多少少都有这种现