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

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
红旗版领航员实车曝光,搭载V8动力,堪称移动堡垒说到自主汽车品牌,不得不提提吉利比亚迪长城长安跟奇瑞,它们可以说是其中的标杆,已经有了可以比肩普通合资品牌的实力。但要说到能代表自主高端的话,也只有红旗汽车才能做到。近日红旗全新旗路特斯燃油时代绝唱,百万价格买到千万设计,8月开启国内预售2019年,路特斯发布的纯电动超跑Evija惊艳了整个行业,从此开启了纯电超跑时代。Evija凭借惊世骇俗的设计,以及超高的性能,刷新了路特斯空气动力学在行业内的地位。三年过去了,越野爱好者的理想之选!柴油动力分时四驱非承载车身说起硬派越野车,很多人第一个想到的应该就是普拉多牧马人兰德酷路泽奔驰G级这样动力强四驱能力高非承载车身的车型,不过,这些车型普遍存在价格高,不适合普通爱好者的问题。今天,小编就为喜AppleWatch比整个瑞士手表行业还牛?你买过它吗?据外媒消息,受AirPodsPro和AppleWatch业绩提振,苹果股票大涨。这两个单品已然成为Apple明星产品,在各自领域内堪称难逢敌手,独孤求败。5年前,AppleWatc花1块钱买两本书,值了抖音直播,花1元听课,还免费赠送6本红宝书,是不是很值呢?偶然间得知的,本来想买个英语课程,学习一下英语,结果英语没赶上,就买了理财课,最终结果嘛多少还有点用,不过那6本书我只领到丰田赛那真的是飘了,这个价格还值得入手吗?随着二胎三胎时代的来临,既SUV以后MPV成为了国内汽车市场上的新宠,看看别克GL8跟本田奥德赛的销量就明白,国人已经开始将MPV作为购车的首选,而其他车企也看中了这个大蛋糕,纷纷1MORE新时尚豆体积超小,佩戴非常舒服的真无线耳机说起真无线耳机,1MORE之前的那款降噪真无线的降噪效果非常好,明显比索尼WF1000XM3还要强。然后1MORE借势推出了新款的时尚豆,开始Tommy听这个名字,以为就是和车一样钱枫事件立案证据不足,现在又如何呢?刚刚网友小艺希望坏人被惩罚举报天天向上主持人钱枫涉嫌强奸她,申称说的每句话都负法律责任,为什么现在才举报,主要是自己一直害怕,焦虑,可是看到钱枫签德艺白皮书时,她发火了,在朋友的帮指导价更便宜,少两个气缸,接近落地近百万还送牌照提到路虎给大家的第一印象恐怕就是油耗高了,毕竟油老虎这个称号可不是浪得虚名的。今天小编就给大家介绍一款比较省油的路虎车,它就是22款揽胜运动版新能源。外观方面,这款车的设计比较简洁金九已然失意,但也让我们发现了意外的惊喜俗话说得好,金九银十是汽车销售的最好时节,不过今年九月却是个例外,失败已经成为定局,根据乘联会发布的消息,今年9月累计卖出158。1万台,同比下降17。4,这还不是重点,重点是这已社死生日现场服务,能让熊猫不走走到上市吗?继海底捞之后,大型社死生日现场又多了一个硬核创造者熊猫不走。这家成立于2017年的年轻烘焙品牌以热情的服务3小时送达的标准迅速火爆出圈,成为生日蛋糕领域的一匹黑马。自2018年初产
华为10月21日全球发布会,预计将重启D系列命名为D50目前,华为将于10月21日下午3点在奥地利维也纳举行全球发布会。很多报道称华为将在中国以外的全球市场推出P50系列。不过最近有消息称海报中并不是华为P50,因为相机凸起的最低点在音山东给予这类企业贷款一次性贴息!比例40最高50万经济导报记者刘勇经济导报记者从山东省财政厅获悉,为促进科技金融结合,缓解科技型中小企业融资难融资贵问题,近日省科技厅省财政厅印发山东省科技成果转化贷款贴息实施细则(暂行),对首次纳节后重点关注板块,日线出现企稳信号2021年中国国际信息通信展览会(PTEXPOCHINA2021)时间2021年9月2729日地点北京国家会议中心展会内容新基建5G人工智能工业互联网物联网车联网新技术先进计算区块重磅!8月纯电动车上险量排名表来了下面是8月份纯电动车上险量排名,数据来自保险机构,看看你的车上榜了没有!注上险量出炉,仅供参考8月电动车上险量排名不出意料,此次宏光MINI依旧稳居第一,远超第二名。而奇瑞eQ1成互联网医院来了,你的医院准备好了吗?(二)其次,医院需具备配套的技术水平。互联网技术的发展成就了各行业的线上应用,也成就了互联网医疗的拓展。但和其他行业不同的是,互联网医疗关系到健康和生命,不容任何误差和误判而给患者带来健新老同堂,小鹏G3G3i配置解读,新势力造车里的老资历随着电动汽车市场的蓬勃发展,想必很多人已经对国内一些新势力造车不再陌生,诸如小鹏蔚来理想等品牌,也开始逐渐为更多大众消费者所接受。其中来自小鹏汽车的G3,可以算得上是该领域元老级产你是不是在做无效私域呢?近期,腾讯智慧零售提出有效私域概念,认为有效私域必须经过多渠道引流创造用户好感度激发社交裂变互动促购深化用户忠诚度五个步骤。私域可以说已经成为营销领域绕不开的词汇。人人都在谈私域,聪明的挑选中央空调!业内人士建议这么选,省电不怕空调病现代生活少不了家电来帮忙!而对付频繁出现的高温天气,空调绝对是家居清凉的利器问题是,多数人都缺乏非常专业的电器知识,一旦要下手挑选空调,那些令人不解的文字符号所代表的涵义,反而让人iQOO8的自适应刷新技术,可以说是太成熟高端了iQOO8发布了电竞记录片,揭露了kpl官方是如何测试游戏的。目前iQOO8是以电竞和性能为主的产品线,这一次iQOO8系列在屏幕上投入了更多的资源,首发三星新一代E5高亮度发光材MIUI口碑有救了,小米11等内测Android12,彻底解决Bug?作为一家手机企业,小米公司最早以MIUI起家,凭借丰富的功能和倾听用户反馈深受喜爱,常年稳居国产定制UI冠军宝座。MIUI12系统推出以来口碑暴跌,糟糕体验令用户感到极度失望,小米我是平头哥,我怕谁?HaylouX1双降噪蓝牙耳机轻体验大家知道,平头哥即蜜獾,属鼬科动物,分布于非洲西亚和南亚,被称为世界上最无所畏惧的动物。蜜獾虽小,爪牙却令人望而生畏全能的身手,不俗的智力和锋利的爪牙,给了蜜獾以小搏大的资本蜜獾的