首页  编辑  

MockUp接口

Tags: /Java/   Date Created:

Mock 接口 Interface 

介绍Mock interface的几种方法 

 

如果使用了接口,例如使用了 Service,那么Mock是个头疼的事情,一般有三种方法,一种是直接实现接口类,只实现相关类方法,其他的存根(stub)方法,直接返为空或者返回null即可。下面分别讲述三种方法的优缺点。 

本文基于 JMock 编写,需要在 pom.xml 中,添加依赖: 

<dependency> 

    <groupId>org.jmockit</groupId> 

    <artifactId>jmockit</artifactId> 

    <version>1.37</version> 

    <scope>test</scope> 

</dependency> 


假设有以下接口和实现类,以及调用接口的使用类: 

Abc.java 接口 

public interface Abc { 

    int method1(); 

    int method2(); 

    int method3(); 

} 


AbcImpl.java 实现类 

package tacos.util.Impl; 

 

import org.springframework.stereotype.Component; 

import tacos.util.Abc; 

 

@Component 

public class AbcImpl implements Abc { 

    @Override 

    public int method1() { 

        return 50; 

    } 

 

    @Override 

    public int method2() { 

        return 0; 

    } 

 

    @Override 

    public int method3() { 

        return 0; 

    } 

} 


Dummy.java 调用接口的实现类 

package tacos.util; 

 

import org.springframework.beans.factory.annotation.Autowired; 

import org.springframework.stereotype.Component; 

 

@Component 

public class Dummy { 

    @Autowired 

    private Abc abc; 

 

    public int callMe() { 

        return abc.method1(); 

    } 

} 


我们要写单测的目标单元为 Dummy.java,下面分别讲述三种 Mock Abc 接口的方法。 

MockUp<Interface> 推荐! 

使用TestNG/JMock,可以直接Mock接口。例如: 

@Test 

public void testMockInterface() throws NoSuchFieldException, IllegalAccessException, InstantiationException { 

    MockUp<Abc> mock = new MockUp<Abc>(){ 

        @Mock 

        public int method1() { 

            return 100; 

        } 

    }; 

 

    Field field = dummy.getClass().getDeclaredField("abc"); 

    field.setAccessible(true); 

    field.set(dummy, mock.getMockInstance()); 

    assertEquals(dummy.callMe(), 100); 

} 


Expectations 

首先,在测试类开头,声明需要Mock的接口变量: 

@Injectable 

接口类 变量名; 


然后在代码中,注入接口变量: 

Field field = dummy.getClass().getDeclaredField("变量名"); 

field.setAccessible(true); 

field.set(dummy, abc); 


最后写上 new Expectation代码即可,即当调用对应接口的某个方法时,返回什么东西,其中方法名,可以使用参数匹配器,Any代表任何参数都返回Mock的数据。 

new Expectations() {{ 

    接口.方法名(Any); 

    result = 需要mock返回的东西; 

}}; 


注意,Expectation,需要每调用一次,都需要写对应的代码,如果某个方法调用了10次该接口的方法,你需要写10个new Expectations! 

示例代码: 

@Injectable 

Abc abc; 

 

@Test 

public void testExpectation() throws NoSuchFieldException, IllegalAccessException { 

    Field field = dummy.getClass().getDeclaredField("abc"); 

    field.setAccessible(true); 

    field.set(dummy, abc); 

    new Expectations() {{ 

        abc.method1(); 

        result = 100; 

    }}; 

    assertEquals(dummy.callMe(), 100); 

} 


Implement interface 

不推荐使用本方法,因为任何接口改动,需要同步改动代码,并且如果添加或者减少接口的方法定义,需要同步修改代码,在不断变动的情况下,非常讨厌,容易导致编译失败和代码合并冲突。 

DummyTest.java 单元测试 

package tacos.util; 

 

import org.junit.Test; 

import org.junit.runner.RunWith; 

import org.springframework.beans.factory.annotation.Autowired; 

import org.springframework.boot.test.context.SpringBootTest; 

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 

import tacos.TacoCloudApplication; 

 

import java.lang.reflect.Field; 

 

import static org.testng.Assert.assertEquals; 

 

@RunWith(SpringJUnit4ClassRunner.class) 

@SpringBootTest(classes = TacoCloudApplication.class) 

public class DummyTest { 

    @Autowired 

    Dummy dummy; 

 

    @Test 

    public void testMethod1() throws NoSuchFieldException, IllegalAccessException { 

        Abc abc = new Abc() { 

            @Override 

            public int method1() { 

                return 100; 

            } 

 

            @Override 

            public int method2() { 

                return 0; 

            } 

 

            @Override 

            public int method3() { 

                return 0; 

            } 

        }; 

 

        Field field = dummy.getClass().getDeclaredField("abc"); 

        field.setAccessible(true); 

        field.set(dummy, abc); 

        assertEquals(dummy.callMe(), 100); 

    } 

 

} 


MockUp Repository

  1. // 实体类
  2. import lombok.Data;
  3. import javax.persistence.Entity;
  4. import javax.persistence.Id;
  5. @Data
  6. @Entity
  7. public class Demo {
  8.     @Id
  9.     private Long id;
  10.     private String name;
  11. }
  12. // CURD类
  13. import org.springframework.data.jpa.repository.JpaRepository;
  14. import org.springframework.stereotype.Repository;
  15. @Repository
  16. public interface DemoRepository extends JpaRepository<DemoString> {
  17. }
  18. // 服务类
  19. import org.springframework.beans.factory.annotation.Autowired;
  20. import org.springframework.data.domain.Example;
  21. import org.springframework.stereotype.Component;
  22. import tacos.model.Demo;
  23. import tacos.model.DemoRepository;
  24. import java.util.List;
  25. @Component
  26. public class DemoService {
  27.     @Autowired
  28.     DemoRepository repository;
  29.     public List<Demo> findAll(Demo demo) {
  30.         return repository.findAll(Example.of(demo));
  31.     }
  32. }
  33. // 单元测试 MockUp Repository 接口
  34. import org.junit.jupiter.api.Test;
  35. import org.junit.runner.RunWith;
  36. import org.mockito.InjectMocks;
  37. import org.mockito.Mock;
  38. import org.mockito.MockitoAnnotations;
  39. import org.mockito.junit.MockitoJUnitRunner;
  40. import org.springframework.data.domain.Example;
  41. import tacos.model.Demo;
  42. import tacos.model.DemoRepository;
  43. import java.util.ArrayList;
  44. import java.util.List;
  45. import static org.junit.jupiter.api.Assertions.assertEquals;
  46. import static org.mockito.Mockito.when;
  47. @RunWith(MockitoJUnitRunner.class)
  48. class DemoServiceTest {
  49.     @InjectMocks
  50.     DemoService service;
  51.     @Mock
  52.     DemoRepository repository;
  53.     public DemoServiceTest() {
  54.         MockitoAnnotations.openMocks(this);
  55.     }
  56.     @Test
  57.     void findAll() {
  58.         Demo demo = new Demo();
  59.         demo.setId(1L);
  60.         List<Demo> expectedList = new ArrayList<>();
  61.         Demo demo1 = new Demo();
  62.         demo1.setId(222L);
  63.         expectedList.add(demo1);
  64.         when(repository.findAll(Example.of(demo))).thenReturn(expectedList);
  65.         List<Demo> list = service.findAll(demo);
  66.         assertEquals(222L, list.get(0).getId());
  67.         assertEquals(1, list.size());
  68.     }
  69. }