【澳门葡京备用网址】mockito解耦合测试,模拟重临数据

   那是那段时日以来结合 PHPunit
文档和大牛们的讲课,想记录下自己攻读到的文化,将来参考补充,完善学到的事物

   那是那段时光的话结合 PHPunit
文档和大牛们的执教,想记录下自己读书到的学问,将来参见补充,完善学到的事物

更加多原创测试技术作品同步更新到微信公众号
:三国测,敬请扫码关怀个体的微信号,感谢!

  Mock测试是单元测试的重中之重艺术之一。

 
 大家一般拔取单测对商厦事情里的代码举办测试,他会支援找到你的一个个纤维的思索不够健全的地点。(纵然大牛说过支付可以先写单测再来写完毕的代码,然则现在的自己感到离那多少个如故有恒河沙数距离来着)

 
 大家一般选用单测对商店事务里的代码举办测试,他会帮助找到您的一个个很小的思量不够周详的地点。(纵然大牛说过支付能够先写单测再来写完结的代码,不过现在的本人倍感离那一个仍然有那一个偏离来着)

 

1、相关网址

 

【澳门葡京备用网址】mockito解耦合测试,模拟重临数据。 

澳门葡京备用网址 1

  官网:

  stub(桩件):

  stub(桩件):

初稿链接:

  项目源码:

    “将对象替换为(可选地)再次回到配置好的重返值的测试替身的履行方法称为上桩(stubbing)”——那是官方文档给出的上桩解释

    “将对象替换为(可选地)重返配置好的再次来到值的测试替身的执行方法称为上桩(stubbing)”——那是法定文档给出的上桩解释

Mock工具Jmockit使用介绍

  api:

  也许那个形容有点抽象来着,差不多的表达了那般个意思:比如说你有一个方法,依赖了数据库查询,当数据库一切正常时,这一个单元测试是OK的,但是当数据库挂掉的时候,那些单测就会挂掉。那就不切合大家 

  也许那一个形容有点抽象来着,大致的表达了如此个趣味:比如说你有一个格局,看重了数据库查询,当数据库一切正常时,那么些单元测试是OK的,然而当数据库挂掉的时候,这么些单测就会挂掉。那就不适合大家 

 

2、什么是Mock测试

单测的一些含义了,单测应该是单一的,只验证你的逻辑这个,所以啊,大家就需求把那一个mock掉,怎么mock呢?就是您可以自定义一个数据库的归来,比如刚才说的本身索要数据库的某部字段重临1的时候,单测就能得逞,

单测的局地意思了,单测应该是纯净的,只验证你的逻辑这一个,所以啊,大家就要求把这一个mock掉,怎么mock呢?就是您可以自定义一个数据库的归来,比如刚才说的自家索要数据库的某部字段重回1的时候,单测就能学有所成,

在写单元测试的长河中大家会意识要求测试的类有为数不少信赖,这个依赖的类如故资源又会有看重,导致在单元测试代码里无法到位打造,大家应对的法子是Mock。简单的讲就是人云亦云这个须要打造的类仍然资源,提须要急需测试的靶子使用。

  Mock 测试就是在测试进程中,对于一些不便于构造(如 HttpServletRequest
必须在Servlet 容器中才能社团出来)或者不简单得到相比较复杂的目的(如 JDBC
中的ResultSet 对象),用一个虚拟的靶子(Mock
对象)来创建以便测试的测试方法。

那会儿我们无法完全依靠数据库,万一被别人改了怎么做?我就自己定义那么些字段再次回到1;未来就是网络堵塞,这些字段在那里都会回来1,是一个定义死了数码,那样就等于把数据库查询给mock了

此刻大家不可能完全依靠数据库,万一被人家改了如何做?我就和好定义这几个字段重临1;未来就是互联网不通,这么些字段在那里都会回到1,是一个定义死了数额,那样就非凡把数据库查询给mock了

1、Mock工具概述

  Mock
最大的意义是帮你把单元测试的耦合分解开,固然您的代码对另一个类依旧接口有依靠,它可以帮你模仿那一个信赖,并帮您作证所调用的依靠的一坐一起。

  然后就足以起来愉悦了······················

  然后就可以开端愉悦了······················

1.1 mock工具列表

可用的Mock Toolkit有很多,相比广泛的有EasyMock,
Jmock和JMockit等等,到底选哪些吧,Jmockit的官网上有个特性相比列表,很详细,他们的机能比较如下:

 

Feature

EasyMock

jMock

Mockito

Unitils Mock

PowerMock:
EasyMock
API

PowerMock:
Mockito
API

JMock
it

Invocation count constraints

 

Recording strict expectations

   

 

Explicit verification

   

 

Partial mocking

 

No method call to switch from record to replay

   

 

No extra code for implicit verification

   

N/A

N/A

 

N/A

No extra "prepare for test" code

   

No need to use @RunWith annotation or base
test class

     

Consistent syntax between void and non-void methods

 

 

   

Argument matchers for some parameters only,
not all

     

   

Easier argument matching based on properties
of value objects

 

Cascading mocks

   

 

Support for mocking multiple interfaces

   

   

Support for mocking annotation types

 

 

Partially ordered expectations

 

       

Mocking of constructors and final/static/native/private methods

       

Declarative application of mocks/stubs to
whole test classes

       

Auto-injection of mocks

   

 

Mocking of "new-ed" objects

       

Support for mocking enum types

       

Declarative mocks for the test class (mock
fields)

   

Declarative mocks for test methods
(parameters, local fields)

           

Special fields for "any" argument matching

           

Use of an special field to specify invocation
results

           

Use of special fields to specify invocation
count constraints

           

Expectations with custom error messages

           

On-demand mocking of unspecified implementation classes

           

Capture of instances created by code under
test

           

Recording & verification of expectations in
loops

           

Support for covariant return types

           

"Duck typing" mocks for state-based tests

           

Single jar file in the classpath is sufficient to
use mocking API

   

 

N/A

N/A

Total

6/32

7/32

13/31

11/31

9/31

14/30

32/32

Total when ignoring JMockit-only features

6/22

7/22

13/21

11/21

9/21

14/20

22/22

 

澳门葡京备用网址 2

   

   

1.2 Mockito简介

EasyMock 以及 Mockito
都因为可以大幅度地简化单元测试的书写进程而被许五人采纳在和谐的做事中,不过那二种Mock 工具都不可以已毕对静态函数、构造函数、私有函数、Final
函数以及系统函数的生搬硬套,可是这几个格局往往是大家在大型系统中须求的效益。

有关更加多Mockito2.0新特点,参考官方介绍文档,里边有关于为何不mock
private的原委,挺有意思的:

 

Mockito 的使用

 

###Maven###

经过Maven管理的,须要在品种的Pom.xml中加进如下的看重:

<dependencies>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.0</version>
<scope>test</scope>
</dependency>
</dependencies>

 

 

在程序中可以import org.mockito.Mockito,然后调用它的static方法。

 

  当大家必要测试A类的时候,要是没有
Mock,则大家须要把全路器重树都打造出来,而利用 Mock
的话就足以将协会分解开,像下边那样:

  在那些进程中本身遭遇了那些障碍:

  在那个进程中我赶上了这一个障碍:

1.2.1 模拟目的

创办 Mock 对象的语法为 mock(class or interface)。

澳门葡京备用网址 3

1.如何mock

1.如何mock

1.2.2 设置对象调用的预想重返值

经过 when(mock.someMethod()).thenReturn(value) 来设定 Mock
对象某个方法调用时的再次回到值。或者采取when(mock.someMethod()).thenThrow(new RuntimeException)
的法子来设定当调用某个方法时抛出的足够。

 

  只需提供mock B 和mock C
的归来即可的,不要求驾驭其底层具体是怎么落到实处的。

2.怎么把mock的靶子传进去

2.怎么把mock的目标传进去

1.2.3 验证被测试类方法

Mock 对象一旦确立便会自动记录自己的互动行为,所以大家可以有接纳的对它的
交互行为举行表明。在 Mockito 中验证 Mock 对象交互行为的法子是
verify(mock).someMethod(…)。最后 Assert() 验证重回值是或不是和预期一样。

 

3、mock使用的景观和利益

 

 

1.2.4 Demo

 Mock 对象的创始

 mock(Class classToMock);
 mock(Class classToMock, String name)
 mock(Class classToMock, Answer defaultAnswer)
 mock(Class classToMock, MockSettings mockSettings)
 mock(Class classToMock, ReturnValues returnValues)

可以对类和接口进行mock对象的创造,创立时得以为mock对象命名。对mock对象命名的功利是调节的时候便于辨认mock对象。

 

Mock对象的梦想行为和再次来到值设定

倘诺大家创立了LinkedList类的mock对象:

LinkedList mockedList = mock(LinkedList.class);

 

  • 实事求是的靶子拥有不确定的表现,发生不可预测效果。(如:股票行情,天气预先报告),我们平日会赶上测试的时候须要去数据库中询问某些数据,不过没有抓住主题的,就到底了然的,即使有一天数据被剔除了依旧被修改了,很难展开回归测试。
  • 诚实对象很难被创制的,真实对象的少数行为很难被触发。
  • 真正对象实际还不设有的。如:某个接口依赖其余系统的服务如故该接口还没支付出来。大家就足以利用mock假诺其归来的数码开展测试。而不用等待其开发完接口,大家再拓展测试。进步开发的频率

  解决情势呢?

  解决方法吗?

1.3 PowerMock简介

PowerMock 是在 EasyMock 以及 Mockito
基础上的扩充,通过定制类加载器等技能,PowerMock
完成了事先涉嫌的所有模拟成效,使其改为大型系统上单元测试中的必备工具。缺点是缺少文档。

mock是模仿目的,用于模拟真实对象的行事。

Powermock紧要用以打桩。比如:方法A的参数须求传入实例B,方法A要求调用B的某部方法B.C()。方法C因为耗时长或者根本没有落到实处或者其余不便于在单元测试中达成等原因,需求伪造重回,此时Powermock即可派上用场。

PowerMock伸张了EasyMock和Mockito框架,扩大了对static和final方法mock帮衬等职能。那里根本根据PowerMock
Mockito API进行介绍。

PowerMock支持JUnit和TestNG,这里基于JUnit。

安装

下载地址:”
Mockito and JUnit including
dependencies”版本。当前版本为”powermock-mockito-junit-1.6.3.zip”。

 

4、一些特点

1.用桩件mock 然后在指定重回(详情见代码呀)

1.用桩件mock 然后在指定重返(详情见代码呀)

1.4 Stub和Mock

###Mock###
所谓的mock,即效仿,模仿的意思。Mock
技术的要紧意义是选择mock工具模拟一些在利用中不简单构造或者相比复杂的目的,从而把测试对象与测试边界以外的靶子隔离开。

###Stub###
Stub,桩。单元测试进度中,对于在行使中不便于构造或者比较复杂的对象,用一个虚构的对象来替代它。从类的落到实处情势上看,stub有一个显式的类完结,根据stub类的复用层次可以兑现为普通类(被三个测试案例复用),内部类(被同一个测试案例的多少个测试方法复用)乃至内部匿名类(只用于当前测试方法)。stub的办法也会有具体的完毕,哪怕不难到唯有一个不难易行的return语句。

###Stub 与 Mock 的区别###
Stub
是在单元测试过程中去替代某些对象来提供所需的测试数据,适用于依照状态的(state-based)测试,关切的是输入和出口。而Mock适用于依据互相的(interaction-based)测试,关怀的是相互进度,不只是模仿状态,还是能模拟模块或对象的作为逻辑并能验证其不易,Mock不必要类的来得完成,直接用工具模拟。

 

  • 可以 mock 具体类而不单止是接口
  • 好几诠释语法糖 – @Mock
  • 根本的辨证错误是 –
    点击堆栈跟踪,看看在测试中的失败验证;点击格外的因由来导航到代码中的实际互动。堆栈跟踪总是干干净净。
  • 允许灵活有序的验证(例如:你轻易有序 verify ,而不是每一个单独的相互)
  • 支撑“详细的用户号码的时光”以及“至少一 次”验证
  • 灵活的验证或利用参数匹配器的 stub
    ( anyObject() , anyString() 或 refEq() 用于基于反射的相当于匹配)
  • 允许创造 自定义的参数匹配器 或者选拔现有的 hamcrest 匹配器

2.得以给这一个被测试的类构造一个public
属性的参数,再在construct里面实例化那几个被mock的类,再将mock传入那个参数里面那几个参数

2.方可给这几个被测试的类构造一个public
属性的参数,再在construct里面实例化那个被mock的类,再将mock传入这一个参数里面那几个参数

2、Jmockit安装

归结考量下来,所以大家的mock工具也接纳了jmockit()

 

 

关于什么运用:

推荐:在Maven 的pom.xml文件中添加以下看重节点:

<dependency>
   <groupId>org.jmockit</groupId> <artifactId>jmockit</artifactId> <version>1.30</version>
   <scope>test</scope>
</dependency>

自然也可以在项目中一贯引入jar包。

 

    

    

3、如何创立一个 mock 对象

JMockit模拟API可用于JUnit 4(版本4.5或更高版本),JUnit
5或TestNG(版本6.2或更高版本)编写测试。
现在让大家看看那几个API是哪些进展模拟的,为了有利于明白,上面引用官网给出的范例代码,同时我们将需要的类库举办引用。

在测试类中,声惠氏个你想要模拟的花色的mock字段,并用@Mocked,@Injectable或@Capturing注释。当模拟类时,@Injectable意味着唯有被分配mock字段的实例将具备mock行为;
否则,被mock的类的有所实例将被mock。

import org.junit.*;
import mockit.*;

public class MyFirstJMockitTest
{
   // Mocked实例(而不是常规的“mock对象”)将自动创建并分配到带注释的mock字段   
@Mocked
   Collaborator mock1; //所有当前和未来的实例都会被mock
   @Injectable
   AnotherDependency anotherMock; //只有一个特定实例被mock

   @Test
   public void myFirstTestMethod()
   {
      //任何mock字段都可以在这里或者类的任何其他测试方法中使用
   }

   @Test
   public void testMethodWithMockParameter(@Mocked YetAnotherDependency testSpecificMock)
   {
      ...
   }

   ...
}

 

只顾:上边的测试类突显了有的见仁见智的事物:第三个测试方法声雅培个参数!
平常,JUnit / TestNG测试方法不相同意有参数。
但是,当使用JMockit时,允许那样的一成不变参数。
一般的话,唯有测试类中大部或富有测试都须要Mock类型时,才使用测试类的Mock字段。
否则,Mock的界定最好仅限于单个测试的Mock参数。
JMockit将一而再关心实例化Mock类型,并且当测试运行器调用测试方法时,将实例分配给mock字段(假如字段不是final)或将其看成参数传递。

 

5、maven配置

 

 

4、Mock范例1

要Mock测试的措施如下:

public class MyObject {
    public String hello(String name){
        return "Hello " + name;
    }
}

应用JMockit编写的单元测试如下:

@Mocked  //用@Mocked标注的对象,不需要赋值,jmockit自动mock
MyObject obj;

@Test
public void testHello() {
    new NonStrictExpectations() {//录制预期模拟行为
        {
            obj.hello("Zhangsan");
            returns("Hello Zhangsan");
            //也可以使用:result = "Hello Zhangsan";
        }
    };
    assertEquals("Hello Zhangsan", obj.hello("Zhangsan"));//调用测试方法
    new Verifications() {//验证预期Mock行为被调用
        {
            obj.hello("Hello Zhangsan");
            times = 1;
        }
    };
}

 

代码已毕后,运行单元测试,结果如下:

澳门葡京备用网址 4

 

 

JMockit也可以分类为非局地模拟与局地模拟,区分在于Expectations块是还是不是有参数,有参数的是一些模拟,反之是非局地模拟。

而Expectations块一般由Expectations类和NonStrictExpectations类定义,类似于EasyMock和PowerMock中的Strict
Mock和平凡Mock。

用Expectations类定义的,则mock对象在运行时不得不依照Expectations块中定义的相继依次调用方法,不可以多调用也不可能少调用,所以可以省略掉Verifications块;

而用NonStrictExpectations类定义的,则尚未那么些限制,所以一旦须求表明,则要添加Verifications块。

上述的例证使用了非局地模拟,上边大家接纳一些模拟来改写上边的测试,代码如下:

 

@Test
public void testHello() {
    final MyObject obj = new MyObject();
    new NonStrictExpectations(obj) {//录制预期模拟行为
        {
            obj.hello("Zhangsan");
            returns("Hello Zhangsan");
            //也可以使用:result = "Hello Zhangsan";
        }
    };
    assertEquals("Hello Zhangsan", obj.hello("Zhangsan"));//调用测试方法
    new Verifications() {//验证预期Mock行为被调用
        {
            obj.hello("Hello Zhangsan");
            times = 1;
        }
    };
}

 

 模仿静态方法:

 

@Test
public void testMockStaticMethod() {
    new NonStrictExpectations(ClassMocked.class) {
        {
            ClassMocked.getDouble(1);//也可以使用参数匹配:ClassMocked.getDouble(anyDouble);
            result = 3;
        }
    };

    assertEquals(3, ClassMocked.getDouble(1));

    new Verifications() {
        {
            ClassMocked.getDouble(1);
            times = 1;
        }
    };
}

仿照私有方法:

如果ClassMocked类中的getTripleString(int)方法指定调用一个民用的multiply3(int)的主意,大家能够使用如下格局来Mock:

@Test
public void testMockPrivateMethod() throws Exception {
    final ClassMocked obj = new ClassMocked();
    new NonStrictExpectations(obj) {
        {
            this.invoke(obj, "multiply3", 1);//如果私有方法是静态的,可以使用:this.invoke(null, "multiply3")
            result = 4;
        }
    };

    String actual = obj.getTripleString(1);
    assertEquals("4", actual);

    new Verifications() {
        {
            this.invoke(obj, "multiply3", 1);
            times = 1;
        }
    };
}

 

1)Junit的maven

 

 

5、Mock案例2

接下去大家用Jmockit完结一个切实可行的单元测试,首先上边是一段Controller的机能代码:

import com.odde.mail.model.Result;
import com.odde.mail.service.MailService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import static java.lang.String.format;

@Controller
@RequestMapping("/mail")
public class MailController {
    private static final Log log = LogFactory.getLog(MailController.class);
    private final ObjectMapper mapper = new ObjectMapper();

    @Autowired
    private MailService mailService;

    @RequestMapping(value = "/send", method = RequestMethod.POST, produces = "text/plain;charset=UTF-8")
    public
    @ResponseBody
    String send(@RequestParam("recipients") String recipients,
                @RequestParam("subject") String subject,
                @RequestParam("content") String content) throws Exception {
        log.debug("mail controller send start");
        log.debug(format("recipients:%s", recipients));
        log.debug(format("subject:%s", subject));
        log.debug(format("content:%s", content));
        Result mailResult = mailService.send(recipients, subject, content);
        String result = mapper.writeValueAsString(mailResult);
        log.debug(format("result:%s", result));
        log.debug("mail controller send finish");
        return result;
    }
}

 

接下去我们看一下Jmockit达成的具体的单元测试代码:

import com.odde.mail.model.Result;
import com.odde.mail.service.MailService;
import mockit.Expectations;
import mockit.Injectable;
import mockit.Tested;
import mockit.integration.junit4.JMockit;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

@RunWith(JMockit.class)
public class MailControllerTest {
    @Tested
    MailController mailController;
    @Injectable
    private MailService mailService;
    @Test
    public void should_return_status_success_when_send_mail_success() throws Exception {
        new Expectations() { {
            mailService.send("test@test.com", "test", "test");
            result = new Result("成功");
        } };
        String result = mailController.send("test@test.com", "test", "test");
        assertThat(result, is("{\"status\":\"成功\"}"));
    }
}
  • @RunWith(JMockit.class):
    指定单元测试的施行类为JMockit.class;
  • @Tested: 这么些是指被测试类,在这么些测试案例中大家要测试的是MailController,所以大家给其打上这些标签;
  • @Injectable: 那些可以将对象举行mock并自行关联到被测试类,而不须要通过其余文件类似spring的布局文件等来拓展关联;
  • @Expectations: mock对象mailService的send方法,让其归来一个Result对象;

做完上边这么些基本就足以了,后边的被测方法调用和表达都跟原来的同等。那样看起来是或不是比原先的单元测试代码少了一部分,也更不难了一部分,最根本的一些是如此的单元测试不拥戴spring的bean定义文件,不必要启动web服务,执行起来速度很快。

 

<dependency>  
  <groupId>junit</groupId>  
  <artifactId>junit</artifactId>  
  <version>4.11</version>  
  <scope>test</scope>  
</dependency> 

====前提

====前提

6、Mock案例3

 

先是照旧是先看一下Service的效益代码,代码也比较简单,就是调用Repository做一些增删改查的动作。

import com.odde.mail.model.Recipient;
import com.odde.mail.model.Result;
import com.odde.mail.repo.RecipientRepository;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class RecipientService {

    @Autowired
    private RecipientRepository recipientRepository;

    public Result add(String username, String email) {
        Recipient recipient = recipientRepository.findByEmail(email);
        Result result;
        if (recipient == null) {
            recipientRepository.save(new Recipient(username, email));
            result = new Result("成功");
        } else {
            result = new Result("失败");
        }
        return result;
    }
}

接着就是它的单元测试代码,我们看一下Jmockit怎么样落实的mock代码:

import com.odde.mail.model.Recipient;
import com.odde.mail.model.Result;
import com.odde.mail.repo.RecipientRepository;
import mockit.Injectable;
import mockit.NonStrictExpectations;
import mockit.Tested;
import mockit.integration.junit4.JMockit;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.List;
import static java.util.Arrays.asList;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;

@RunWith(JMockit.class)
public class RecipientServiceTest {

    @Tested
    private RecipientService recipientService;

    @Injectable
    private RecipientRepository recipientRepository;

    @Test
    public void should_return_success_when_add_recipient_not_exist() throws Exception {
        Result result = recipientService.add("Tom", "test@test.com");
        assertThat(result.getStatus(), is("成功"));
    }
}

 

 

相持Controller
Test那里少了一步对recipientRepository对象findByEmail方法的mock,因为一旦不通过Expectations进行格局mock的话,方法会默认重返null,而我们要测试的情况正是要求findByEmail方法再次来到null,所以mock方法这一步咱们也省了。改写后的全部代码也比原先的少了累累,而且速度更快。

 

2)mockito的maven

    我想测试的是这样一个方法:switchClothes($username)
 —-通过名字查询数据库,性别是1的,就回来裤子,是0的,就回来裙子;

    我想测试的是那般一个方法:switchClothes($username)
 —-通过名字查询数据库,性别是1的,就回来裤子,是0的,就回去裙子;

7、Mock使用指出

 

JMockit功能相当有力,不仅能够轻松处理地点的那一个测试场景,还足以对static,final,private等方法开展mock,可以让你的单元测试毫无阻拦的拓展。
可是借使过度的行使Mock框架,会让职能代码的真的难题被遮住。本来单元测试的宏图可以让你发觉功用代码上的有些布置是不是创制,比如有没有紧耦合等,但选取JMockit可以让你在设计不创造的代码上也可以轻松地拓展单元测试,那样你就很难发现效果代码上的难点了。
从而指出JMockit等类似的mock框架依然要审慎运用,首先要力保效益代码设计合理,满意面向对象设计的需要,再来考虑升高单元测试功效的问题。

除此以外,Mock的函数是不总括到单元测试覆盖率里边的,如下图所示:

 

 

 

澳门葡京备用网址 5

 

 

注意:大家mock了hello方法,不过在Ecl艾玛中显得覆盖率为0%。

 

    <dependency>  
          <groupId>org.mockito</groupId>  
          <artifactId>mockito-all</artifactId>  
          <version>1.9.5</version>  
          <scope>test</scope>  
      </dependency>  

          

          

8、紧要:注意事项以及调节中遇到的题目

6、使用

<?php
        Class Switch{

            public $server;

       public function __construct() {

           $this->srv=new database();

           }

           public function switchClothes($username){ 

         $gender=$this->server->find("id=$username");
         if($gender==0){ 

          return "裙子"; 
        }else{ 
  
         return "裤子"; 
        } 
      } 
    }  
<?php
        Class Switch{

            public $server;

       public function __construct() {

           $this->srv=new database();

           }

           public function switchClothes($username){ 

         $gender=$this->server->find("id=$username");
         if($gender==0){ 

          return "裙子"; 
        }else{ 
  
         return "裤子"; 
        } 
      } 
    }  

题材1 编译报错方法名无法找到

在pom.xml文件中,注意依赖次序,JMockit一定要在JUnit以前,否则不难出现编译报错方法名找不到之类的奇葩难题:

澳门葡京备用网址 6

 

 

 

  首先咱们必要引入静态资源

 

 

标题2 报错Jmockit开端化十分

引用的本子必须保持一致,可以在build
path里查看是还是不是是自己用的版本,否则会报错Jmockit开头化非凡:

澳门葡京备用网址 7

 

 

import static org.mockito.Mockito.*;  
import static org.junit.Assert.*; 

    查询数据库我封装了一个Database类里面的: find()

    查询数据库我封装了一个Database类里面的: find()

难题3 版本造成java.lang.NoSuchMethodError

Junit使用新型版本是4.12。系统默许的junit版本太低了。会报相当如下:

 

java.lang.NoSuchMethodError:
org.junit.runner.Request.classWithoutSuiteMethod(Ljava/lang/Class;)Lorg/junit/runner/Request;
at
org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createFilteredTest(JUnit4TestLoader.java:76)
at
org.eclipse.jdt.internal.

澳门葡京备用网址,改为新型版本,Junit运行如常:

<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

 

 

 

 

问题4 报错cannot be resolved to a type

 

调剂进度中报错:

xxx cannot be resolved to a
type

 

竭泽而渔办法,在发出错误的系列上单击鼠标右键-〉Properties,选中“Resource”,右边Text
file encoding拔取“Other:UTF-8”,点击“Apply”按钮。

 

澳门葡京备用网址 8

 

附录:参考文档一览

JMockit官网:

拔取JMockit编写java单元测试:

 

谢谢阅读,小编原创技术文章,转发请评释出处

1)验证行为

====先导写测试

====伊始写测试

@Test  
public void verify_behaviour(){  
    //模拟创建一个List对象  
    List mock = mock(List.class);  
    //使用mock的对象  
    mock.add(1);  
    mock.clear();    //清空mock对象 
    //验证add(1)和clear()行为是否发生  
    verify(mock).add(1);  
    verify(mock).clear();  
}  

       
 首先我索要测试的是switchClothes那么些类,可是在这些类里我要求去通过实例化database这么些类用select方法,查询数据库再来获得本人究竟是要裤子依然裙子。所以,,真的是太难为了,我只是独自的想测测那个点子的逻辑好么,万一数据库挂了,万一那么些username不存在,我难道还要越发去数据库创建那样一条数据么,太劳碌了也不够好。万一须求测试包蕴更新数据的形式,难道还要真的修改数据么?

       
 首先自己索要测试的是switchClothes这一个类,可是在那些类里我急需去通过实例化database这些类用select方法,查询数据库再来获得自身到底是要裤子依旧裙子。所以,,真的是太难为了,我只是一味的想测测那个点子的逻辑好么,万一数据库挂了,万一以此username不设有,我难道还要专门去数据库成立那样一条数据么,太难为了也不够好。万一须求测试包罗更新数据的法门,难道还要真的修改数据么?

 

       
 stub就华丽丽降临了。大姑再也不用担心我要去操作数据库,再也不担心接口不通神马的了。

       
 stub就华丽丽降临了。姑姑再也不用担心自己要去操作数据库,再也不担心接口不通神马的了。

 2)模拟大家所企盼的结果

    澳门葡京备用网址 9

    澳门葡京备用网址 10

public void when_thenReturn(){  
    //mock一个Iterator类  
    Iterator iterator = mock(Iterator.class);  
    //预设当iterator调用next()时第一次返回hello,第n次都返回world  
    when(iterator.next()).thenReturn("hello").thenReturn("world");  
    //使用mock的对象  
    String result = iterator.next() + " " + iterator.next() + " " + iterator.next();  
    //验证结果  
    assertEquals("hello world world",result);  
}  

    我可以对那几个类举行上桩。说通俗点,我以为就是对那些类进行了一个模拟,做了一个假的database类;

    我得以对这么些类举行上桩。说通俗点,我认为就是对这几个类举办了一个效仿,做了一个假的database类;

 

    如上如  A=switchClothes  B=database类  D=数据库   C=stub
的越发类

    如上如  A=switchClothes  B=database类  D=数据库   C=stub
的那几个类

 

    本来应该是A调用B,B查询数据库的.

    本来应该是A调用B,B查询数据库的.

@Test(expected = IOException.class)  
public void when_thenThrow() throws IOException {  
    OutputStream outputStream = mock(OutputStream.class);  
    OutputStreamWriter writer = new OutputStreamWriter(outputStream);  
    //预设当流关闭时抛出异常  
    doThrow(new IOException()).when(outputStream).close();  
    outputStream.close();  
}  

    然而C的存在就走了革命那条线,C不会去查数据库,C是被我掌控的,我得以指定里面的find()方法重回1要么0
至少在A看来它和B一样,反正会给本人再次回到个0或者1来的。那就相当于C
将A与B,D那几个连串隔绝了开来,收缩了耦合;

    不过C的存在就走了甲寅革命那条线,C不会去查数据库,C是被我掌控的,我可以指定里面的find()方法再次来到1要么0
至少在A看来它和B一样,反正会给自身回去个0或者1来的。那就等于C
将A与B,D这些系统隔绝了开来,裁减了耦合;

3)参数匹配

    然后,就可以开首社团自己必要的C了。

    然后,就可以伊始社团自己必要的C了。

@Test  
public void with_arguments(){  
    Comparable comparable = mock(Comparable.class);  
    //预设根据不同的参数返回不同的结果  
    when(comparable.compareTo("Test")).thenReturn(1);  
    when(comparable.compareTo("Omg")).thenReturn(2);  
    assertEquals(1, comparable.compareTo("Test"));  
    assertEquals(2, comparable.compareTo("Omg"));  
    //对于没有预设的情况会返回默认值  
    assertEquals(0, comparable.compareTo("Not stub"));  
}  

    

    

  除了匹配制定参数外,还是能协作自己想要的妄动参数

<?php
use PHPUnit\Framework\TestCase;

class StubTest extends TestCase
{


    public function testStub()
    {
        // 为database类建立桩件。
        $stub = $this->getMockBuilder("database")//类名
                             ->setMethods(array('find')) //可以是多个方法
                              ->getMock();

        // 配置桩件。
        $stub->method('find')//想要设置返回值的方法
             ->willReturn(0);//设置返回值 
     $ser=new Switch();
     $ser->server=$stub;       //将桩件赋值给server
     $ser->switchClother("1"); //调用被测试的方法

       // 现在调用将返回 '裙子'。

     $this->assertEquals('裙子', $stub->find()); } } ?>
<?php
use PHPUnit\Framework\TestCase;

class StubTest extends TestCase
{


    public function testStub()
    {
        // 为database类建立桩件。
        $stub = $this->getMockBuilder("database")//类名
                             ->setMethods(array('find')) //可以是多个方法
                              ->getMock();

        // 配置桩件。
        $stub->method('find')//想要设置返回值的方法
             ->willReturn(0);//设置返回值 
     $ser=new Switch();
     $ser->server=$stub;       //将桩件赋值给server
     $ser->switchClother("1"); //调用被测试的方法

       // 现在调用将返回 '裙子'。

     $this->assertEquals('裙子', $stub->find()); } } ?>
@Test  
public void with_unspecified_arguments(){  
    List list = mock(List.class);  
    //匹配任意参数  
    when(list.get(anyInt())).thenReturn(1);  
    when(list.contains(argThat(new IsValid()))).thenReturn(true);  
    assertEquals(1, list.get(1));  
    assertEquals(1, list.get(999));  
    assertTrue(list.contains(1));  
    assertTrue(!list.contains(3));  
}  

private class IsValid extends ArgumentMatcher<List>{  
    @Override  
    public boolean matches(Object o) {  
        return o == 1 || o == 2;  
    }  
}  

 这就是C了。

 这就是C了。

  需求小心的是一旦你接纳了参数匹配,那么所有的参数都无法不通过matchers来合作

 单测的时候,走藏红色那条路就行了。

 单测的时候,走黄色那条路就行了。

@Test  
public void all_arguments_provided_by_matchers(){  
    Comparator comparator = mock(Comparator.class);  
    comparator.compare("nihao","hello");  
    //如果你使用了参数匹配,那么所有的参数都必须通过matchers来匹配  
    verify(comparator).compare(anyString(),eq("hello"));  
    //下面的为无效的参数匹配使用  
    //verify(comparator).compare(anyString(),"hello");  
}  

 all

 all

4)验证方便的调用次数

 

 

@Test  
public void verifying_number_of_invocations(){  
    List list = mock(List.class);  
    list.add(1);  
    list.add(2);  
    list.add(2);  
    list.add(3);  
    list.add(3);  
    list.add(3);  
    //验证是否被调用一次,等效于下面的times(1)  
    verify(list).add(1);  
    verify(list,times(1)).add(1);  
    //验证是否被调用2次  
    verify(list,times(2)).add(2);  
    //验证是否被调用3次  
    verify(list,times(3)).add(3);  
    //验证是否从未被调用过  
    verify(list,never()).add(4);  
    //验证至少调用一次  
    verify(list,atLeastOnce()).add(1);  
    //验证至少调用2次  
    verify(list,atLeast(2)).add(2);  
    //验证至多调用3次  
    verify(list,atMost(3)).add(3);  

 

 

5)模拟方法体抛出至极

       

       

@Test(expected = RuntimeException.class)  
public void doThrow_when(){  
    List list = mock(List.class);  
    doThrow(new RuntimeException()).when(list).add(1);  
    list.add(1);  
}  

   

   

6)验证执行各种

    

    

@Test  
public void verification_in_order(){  
    List list = mock(List.class);  
    List list2 = mock(List.class);  
    list.add(1);  
    list2.add("hello");  
    list.add(2);  
    list2.add("world");  
    //将需要排序的mock对象放入InOrder  
    InOrder inOrder = inOrder(list,list2);  
    //下面的代码不能颠倒顺序,验证执行顺序  
    inOrder.verify(list).add(1);  
    inOrder.verify(list2).add("hello");  
    inOrder.verify(list).add(2);  
    inOrder.verify(list2).add("world");  
}  

   

   

7)确保模拟指标上无互动发生

          

          

@Test  
public void verify_interaction(){  
    List list = mock(List.class);  
    List list2 = mock(List.class);  
    List list3 = mock(List.class);  
    list.add(1);  
    verify(list).add(1);  
    verify(list,never()).add(2);  
    //验证零互动行为  
    verifyZeroInteractions(list2,list3);  
}  

 

 

8)找出冗余的竞相(即未被证实到的)

  

  

@Test(expected = NoInteractionsWanted.class)  
public void find_redundant_interaction(){  
    List list = mock(List.class);  
    list.add(1);  
    list.add(2);  
    verify(list,times(2)).add(anyInt());  
    //检查是否有未被验证的互动行为,因为add(1)和add(2)都会被上面的anyInt()验证到,所以下面的代码会通过  
    verifyNoMoreInteractions(list);  

    List list2 = mock(List.class);  
    list2.add(1);  
    list2.add(2);  
    verify(list2).add(1);  
    //检查是否有未被验证的互动行为,因为add(2)没有被验证,所以下面的代码会失败抛出异常  
    verifyNoMoreInteractions(list2);  
}  

  

  

9)使用注脚的方法来神速模拟

  

  

  在上面的测试中我们在各种测试方法里都mock了一个List对象,为了防止重复的mock,是测试类更拥有可读性,大家得以拔取上面的(@Mock)注明格局来很快模拟目标:

@Mock  
private List mockList;   

  大家再用声明的mock对象试试

@Test  
public void shorthand(){  
    mockList.add(1);  
    verify(mockList).add(1);  
}  

  运行那个测试类你会意识报错了,mock的对象(mockList)为NULL,为此大家必须在基类中添加开端化mock的代码

public class MockitoExample2 {  
    @Mock  
    private List mockList;  

    public MockitoExample2(){  
        MockitoAnnotations.initMocks(this);  
    }  

    @Test  
    public void shorthand(){  
        mockList.add(1);  
        verify(mockList).add(1);  
    }  
}  

  或者选拔built-in runner:MockitoJUnitRunner

@RunWith(MockitoJUnitRunner.class)  
public class MockitoExample2 {  
    @Mock  
    private List mockList;  

    @Test  
    public void shorthand(){  
        mockList.add(1);  
        verify(mockList).add(1);  
    }  
}  

  越多的诠释还有@Captor,@Spy,@InjectMocks

10)延续调用

@Test(expected = RuntimeException.class)  
public void consecutive_calls(){  
    //模拟连续调用返回期望值,如果分开,则只有最后一个有效  
    when(mockList.get(0)).thenReturn(0);  
    when(mockList.get(0)).thenReturn(1);  
    when(mockList.get(0)).thenReturn(2);  
    when(mockList.get(1)).thenReturn(0).thenReturn(1).thenThrow(new RuntimeException());  
    assertEquals(2,mockList.get(0));  
    assertEquals(2,mockList.get(0));  
    assertEquals(0,mockList.get(1));  
    assertEquals(1,mockList.get(1));  
    //第三次或更多调用都会抛出异常  
    mockList.get(1);  
}  

11)使用回调生成期望值

@Test  
public void answer_with_callback(){  
    //使用Answer来生成我们我们期望的返回  
    when(mockList.get(anyInt())).thenAnswer(new Answer<Object>() {  
        @Override  
        public Object answer(InvocationOnMock invocation) throws Throwable {  
            Object[] args = invocation.getArguments();  
            return "hello world:"+args[0];  
        }  
    });  
    assertEquals("hello world:0",mockList.get(0));  
    assertEquals("hello world:999",mockList.get(999));  
}   

12)监控真实对象

  使用spy来监督真实的对象,需求小心的是此时我们要求严酷的选择when-then语句,而改用do-when语句

@Test(expected = IndexOutOfBoundsException.class)  
public void spy_on_real_objects(){  
    List list = new LinkedList();  
    List spy = spy(list);  
    //下面预设的spy.get(0)会报错,因为会调用真实对象的get(0),所以会抛出越界异常  
    //when(spy.get(0)).thenReturn(3);  

    //使用doReturn-when可以避免when-thenReturn调用真实对象api  
    doReturn(999).when(spy).get(999);  
    //预设size()期望值  
    when(spy.size()).thenReturn(100);  
    //调用真实对象的api  
    spy.add(1);  
    spy.add(2);  
    assertEquals(100,spy.size());  
    assertEquals(1,spy.get(0));  
    assertEquals(2,spy.get(1));  
    verify(spy).add(1);  
    verify(spy).add(2);  
    assertEquals(999,spy.get(999));  
    spy.get(2);  
}  

13)修改对未预设的调用再次来到默许期望值

@Test  
public void unstubbed_invocations(){  
    //mock对象使用Answer来对未预设的调用返回默认期望值  
    List mock = mock(List.class,new Answer() {  
        @Override  
        public Object answer(InvocationOnMock invocation) throws Throwable {  
            return 999;  
        }  
    });  
    //下面的get(1)没有预设,通常情况下会返回NULL,但是使用了Answer改变了默认期望值  
    assertEquals(999, mock.get(1));  
    //下面的size()没有预设,通常情况下会返回0,但是使用了Answer改变了默认期望值  
    assertEquals(999,mock.size());  
}  

14)捕获参数来一发断言

       @Test  
public void capturing_args(){  
    PersonDao personDao = mock(PersonDao.class);  
    PersonService personService = new PersonService(personDao);  

    ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);  
    personService.update(1,"jack");  
    verify(personDao).update(argument.capture());  
    assertEquals(1,argument.getValue().getId());  
    assertEquals("jack",argument.getValue().getName());  
}  

 class Person{  
    private int id;  
    private String name;  

    Person(int id, String name) {  
        this.id = id;  
        this.name = name;  
    }  

    public int getId() {  
        return id;  
    }  

    public String getName() {  
        return name;  
    }  
}  

interface PersonDao{  
    public void update(Person person);  
}  

class PersonService{  
    private PersonDao personDao;  

    PersonService(PersonDao personDao) {  
        this.personDao = personDao;  
    }  

    public void update(int id,String name){  
        personDao.update(new Person(id,name));  
    }  
}  

15)真实的一对mock

@Test  
public void real_partial_mock(){  
    //通过spy来调用真实的api  
    List list = spy(new ArrayList());  
    assertEquals(0,list.size());  
    A a  = mock(A.class);  
    //通过thenCallRealMethod来调用真实的api  
    when(a.doSomething(anyInt())).thenCallRealMethod();  
    assertEquals(999,a.doSomething(999));  
}  


class A{  
    public int doSomething(int i){  
        return i;  
    }  
}  

16)重置mock

@Test  
public void reset_mock(){  
    List list = mock(List.class);  
    when(list.size()).thenReturn(10);  
    list.add(1);  
    assertEquals(10,list.size());  
    //重置mock,清除所有的互动和预设  
    reset(list);  
    assertEquals(0,list.size());  
}  

   后边还有在一个类中调用别的一个类的方法,大家盼望模拟那样类措施的回到,如:Controller中调用了Service的办法,大家要效仿Service方法再次来到的多寡,Sevice调用了Dao层,大家要效仿重回Dao层的主意,在后头会补上。

  致谢:感谢您的翻阅!

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website