mockito单元测试

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mockito单元测试相关的知识,希望对你有一定的参考价值。

参考技术A 1、什么是Mock?

mock是在测试过程中,对于一些不容易构造/获取的对象,创建一个mock对象来模拟对象的行为。比如说你需要调用B服务,可是B服务还没有开发完成,那么你就可以将调用B服务的那部分给Mock掉,并编写你想要的返回结,SpringBoot默认的Mock框架是Mockito,和junit一样,只需要依赖spring-boot-starter-test就可以了。

2、测试过程中常用注解

@RunWith 指定运行环境,例:

@RunWith(SpringRunner.class) Junit运行Spring的测试环境

@RunWith(MockitoJUnitRunner.class) Junit运行Mockito的运行环境,不会加载springboot上下文

@SpringBootTest 加载springboot上下文配置

@WebMvcTest(xxxController.class) 用于测试单个Controller,提供了自配置的MocMvc,可以不启动整个应用就可以以http请求的方 式测试Controller,不过这个注解不会去扫描@Service,@Mapper等注解,当调用这些服务时最好提前打桩,不然会报Error create bean这类异常

@Mock 用于模拟一个服务,例如测试的时候需用调用B服务,但是B服务没写 好,这是可以先Mock一个B服务

@InjectMocks 标注服务的实现类,创建一个实例,其余用@Mock注解创建的mock将被注入到用该实例中

@Before 每个测试方法执行前,执行一次

@After 每个测试方法执行完,执行一次

@Test 标注测试方法

3、测试Service的简单样例,( 注:目前项目中单元测试主要测试的是逻辑,第三方api及dao层都会屏蔽掉,所以不用加载整个上下文,建议用这种方式测试)

@RunWith(MockitoJUnitRunner.class)

public classTest

@Mock

private DataApi dataApi;

@InjectMocks

private DataServiceImpl dataService;

/*

* 准备数据

*/

@Before

public void baseInfo()

Entity entity=new Entity();

entity.setEndTime(1652544000);

//打桩,当DataService去调用dataApi的selectByPrimaryKey时,会返回模拟的entity数据,anyLong()指任意Long型参数

doReturn(entity).when(dataApi).selectByPrimaryKey(anyLong());

 

@Test

public void testGetData()

Stirng isOk=dataService.getData(123);

Assert.state("Ok".equals(isOk))//断言,返回预期结果,测试通过

// mock本类中的其他方法

DataServiceImpl dataService1 = Mockito.spy(dataService);

doReturn(false).when(dataService1).getData2(anyList(), any());

// 若需要多次调用一个方法,返回不同的结果,可以按顺序进行return;

when(dataService1.getData2(anyList(), any())).thenReturn("OK").thenReturn(null);

 

// 对测试类中私有变量赋值

// private int maxActive;

@Test

public void dataSourceTest()

try

    Field apiField = FourthDaoConfiguration.class.getDeclaredField("maxActive");

    FieldSetter.setField(fourthDaoConfiguration, apiField, 3);

    DruidDataSource result =fourthDaoConfiguration.dataSource();

    Assert.assertNotNull(result);

    catch (Exception e)

   



// 对测试方法中返回的公用类做mock

@Test

public void updateSystemBalanceTest()

try

        Long userId =1L;

        Integer amount =10;

        String actionCause ="aa";

        String swiftNumber ="aa";

        RLock fairLock =mock(RedissonLock.class);

        doReturn(true).when(fairLock).tryLock(50, 60, TimeUnit.SECONDS);

        doNothing().when(fairLock).unlock();

        doReturn(fairLock).when(redissonClient).getLock(anyString());

        int result =partnerAccountActionManager.updateSystemBalance(userId, amount, actionCause, swiftNumber);

        Assert.assertTrue(result >0);

    catch (Exception e)

e.printStackTrace();

   





4、测试Controller简单样例,模仿http发请求,载入springboot的上下文

@RunWith(SpringRunner.class)

@SpringBootTest

public class MockMvcTest

// 注入web环境的ApplicationContext容器

@Autowired

private WebApplicationContext context;

/**

* 模拟mvc测试对象

*/

private MockMvc mockMvc;

@Before

public void before() throws Exception

//获取mockmvc对象实例

mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();

 

/*

mockMvc.perform 用于发送请求   

MockMvcRequestBuilders用于指定请求方式,参数,媒体类型

*/

@Test

public void getInfo() throws Exception

mockMvc.perform(

MockMvcRequestBuilders.get("/xxx/getInfo")//请求方式,指定URL

.param("xxxx","1489")//请求参数

.param("xxxx","232")

.param("xxxx","0")

.contentType(MediaType.APPLICATION_FORM_URLENCODED)//媒体类型 

                      )

.andExpect(MockMvcResultMatchers.jsonPath("$.code").value(0))//校验响应结果

.andReturn();//返回结果

 

android单元测试框架Mockito使用

单元测试,早些年时常听到这个概念,真的有去做的确实少,基本都是自己功能上的测试,开发完测试跑一边没啥问题就发布了。这几天花了点心思看了下MockIto框架,记录博文。

  • MockIto官网文档在https://static.javadoc.io/org.mockito/mockito-core/2.23.0/org/mockito/Mockito.html。
  • MockIto框架是基于原生JUnit4,JUnit4是整个单元测试的基础,他能够帮我我们开发者更快,更高效的进行单元测试

1.在mvp的模式上,我们建立一个P层叫LuckinTestPresenter,大概流程为:注册-》验证此账号是否允许注册,允许-》注册成功,具体为

    /**
     * 注册账号密码
     * @param phone 账号
     * @param passWord 密码
     */
    public void register(String phone, String passWord) {
         System.out.println("到达register");
    }
    /**
     * 验证是否可以注册
     * @param phone
     * @param passWord
     */
    public void verification(String phone, String passWord) {
        System.out.println("到达verification");
        if (!isLimit()) {
            register(phone, passWord);
        }
    }
    /**
     * 注册之前检查这个手机号是否被限制
     * @return
     */
    public boolean isLimit() {
        return false;
    }

2:我们现在要在单元测试中,验证点击注册的时候程序是否有跑过verification方法,那么我们的单元测试案例为

public class LuckinPresenterTest {
    @Test
    public void check() {
        //mockito会模拟LoginPresenterTest这个需要测试的class,返回一个LoginPresenterTest对象
        LuckinTestPresenter luckinTestPresenter = Mockito.mock(LuckinTestPresenter.class);
        //主动调用验证方法
        luckinTestPresenter.verification("2018091280", "word");
        //现在我们要了利用MockIto验证程序到这为止,是否走到了register(),方法如下
        Mockito.verify(luckinTestPresenter).register("2018091280", "word");
    }
}

run发现报错
技术分享图片
为啥呢,因为你要验证的register()并没有被调用,为啥呢,看程序,应该执行的呀,这里需要注意的就是所哟Mock标记的类都是虚拟的,返回值都是null,也就是说你无法用一个为null的对象去调用register方法。如果我就要这么做呢,那就用spy标注吧。修改案例改为:

public class LuckinPresenterTest {
    @Test
    public void check() {
        //mockito会模拟LoginPresenterTest这个需要测试的class,返回一个LoginPresenterTest对象
        LuckinTestPresenter luckinTestPresenter = Mockito.spy(LuckinTestPresenter.class);
        //主动调用验证方法
        luckinTestPresenter.verification("2018091280", "word");
        //现在我们要了利用MockIto验证程序到这为止,是否走到了register(),方法如下
        Mockito.verify(luckinTestPresenter).register("2018091280", "word");
    }
}

run结果为-》成功
技术分享图片
2:现在有一个需求,我要测试当我isLimit()返回都会true时程序有没有走register,我又不想动原p层代码,那咋办呢,有办法,我们修改为

public class LuckinPresenterTest {
    @Test
    public void check() {
        //mockito会模拟LoginPresenterTest这个需要测试的class,返回一个LoginPresenterTest对象
        LuckinTestPresenter luckinTestPresenter = Mockito.spy(LuckinTestPresenter.class);
        //主动调用验证方法
        Mockito.when(luckinTestPresenter.isLimit()).thenReturn(true);//控住islimit返回true
        luckinTestPresenter.verification("2018091280", "word");
        //现在我们要了利用MockIto验证程序到这为止,是否走到了register(),方法如下
        Mockito.verify(luckinTestPresenter).register("2018091280", "word");
    }
}

run结果为技术分享图片
程序走过了verification,之后报错(就说明mock验证失败,程序没有走到register方法,因为你已经把isLimit返回值设为了true)。
相关方法为:

public class LuckinPresenterTest {
    @Test
    public void check() {
        //mockito会模拟LoginPresenterTest这个需要测试的class,返回一个LoginPresenterTest对象
        LuckinTestPresenter luckinTestPresenter = Mockito.spy(LuckinTestPresenter.class);

        //控住isTourise返回true
        Mockito.when(luckinTestPresenter.isLimit()).thenReturn(true);

        //主动验证操作
        luckinTestPresenter.verification("2018091280", "word");

        //现在我们要了利用MockIto验证程序到这为止,是否走到了register(),方法如下
        Mockito.verify(luckinTestPresenter).register("2018091280", "word");

        //验证register的方法是否调用,并且是否为1次,并且参数一致
        Mockito.verify(luckinTestPresenter, Mockito.times(1)).register("2018091280", "word");

        //验证register的方法从未调用过
        Mockito.verify(luckinTestPresenter, Mockito.never()).register("2018091280", "word");

        //验证register的方法是否调用,并且是否为1次,参数忽略
        Mockito.verify(luckinTestPresenter, Mockito.times(1)).register(Mockito.anyString(), Mockito.anyString());

    }
}

以上是关于mockito单元测试的主要内容,如果未能解决你的问题,请参考以下文章

JUnit + Mockito 单元测试

Mockito单元测试

一文让你快速上手 Mockito 单元测试框架

一文让你快速上手 Mockito 单元测试框架

Mockito单元测试

Mockito单元测试保姆级实战(一个java Mock测试框架)