1. jar 包选择

<!-- 单侧相关 统一管理 -->
            <dependency>
                <groupId>org.mockito</groupId>
                <artifactId>mockito-all</artifactId>
                <version>${mockito.version}</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.mockito</groupId>
                <artifactId>mockito-core</artifactId>
                <version>${mockito.version}</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>5.3.19</version>
                <scope>compile</scope>
            </dependency>
            <dependency>
                <groupId>org.powermock</groupId>
                <artifactId>powermock-api-mockito</artifactId>
                <version>1.6.3</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.powermock</groupId>
                <artifactId>powermock-module-junit4</artifactId>
                <version>1.6.3</version>
                <scope>test</scope>
            </dependency>

2. 要测试的目标方法, 注意是私有方法

Java单元测试Mock一个私有方法_java-ee

 以及这个方法里再次调用的方法, 这个方法是查询数据库方法 

Java单元测试Mock一个私有方法_java_02

3. 单元测试的编写

        说几点编写单元测试类的注意事项 :

               1. @InjectMocks 标注的字段会创建一个实例, 其余用 @Mock(或@Spy)注解创建的 mock 字段将被注入到该实例中

                2. 在这个测试类中, sqpDmUserRelationService 的实例会被注入到 decisionFlowService, 类似在业务层里注入dao层对象

                3. 因为要测试的代码里有数据库查询的操作, 但是我们写的是单侧, 不会真正的查询数据库, 所以需要自己 mock 数据库查询的数据, 首先创建一个集合, 在集合里添加对象, 用于表示这是查询数据库后会返回的数据

                之后这行代码很关键

             

when(sqpDmUserRelationService.getUserGroupInfo(any())).thenReturn(sqpDmUserRelationList);

                这行代码表示调用 getUserGroupInfo() 方法, 使用任意参数 any(), 模拟数据库查询, 

之后返回我们刚才创建的集合, 这样就完成了模拟数据库的查询, 后面这个查询结果还会使用到

                4. 创建执行目标方法的对象, 由于我们本次测试的是私有方法, 这种情况在项目会有很多, 所以需要使用PowerMock框架, 并且使用 PowerMockito.spy(decisionFlowService) 方法, 参数一定要传递我们刚才用 @InjectMocks 创建的实体字段对象, 这样会把 decisionFlowService 对象引用和 sqpDmUserRelationService 对象引用都传递到我们要测试的目标方法里

                5. 执行目标方法, PowerMockito.when(spy, "getUserGroupDynamicSql", "城市", 1).thenReturn(Lists.newArrayList());

                使用 PowerMockito,when() 执行目标方法, 第一个参数是代理对象, 第二个参数是我们要调用的私有方法的方法名称, 第三个参数是方法的参数

@RunWith(MockitoJUnitRunner.class)
@PrepareForTest({DecisionFlowServiceImpl.class, SqpDmUserRelationServiceImpl.class, SqpDmUserRelationService.class})
public class DecisionFlowServiceImplTest {

    @Mock
    private SqpDmUserRelationServiceImpl sqpDmUserRelationService;

    @InjectMocks
    private DecisionFlowServiceImpl decisionFlowService;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testGetCountDecisionFlowNum() throws Exception {
        // 模拟mysql数据
        List<SqpDmUserRelation> sqpDmUserRelationList = Lists.newArrayList();
        SqpDmUserRelation var1 = new SqpDmUserRelation();
        var1.setEmployeeCode("060423665");
        var1.setDutyType("大区");
        var1.setDutyValue("东区");
        sqpDmUserRelationList.add(var1);

        SqpDmUserRelation var3 = new SqpDmUserRelation();
        var3.setEmployeeCode("060423665");
        var3.setDutyType("店铺区");
        var3.setDutyValue("AD11111");
        sqpDmUserRelationList.add(var1);

        SqpDmUserRelation var2 = new SqpDmUserRelation();
        var2.setEmployeeCode("210902495");
        var2.setDutyType("店铺");
        var2.setDutyValue("AD1111");
        sqpDmUserRelationList.add(var2);

        // mock mysql查询
        when(sqpDmUserRelationService.getUserGroupInfo(any())).thenReturn(sqpDmUserRelationList);
        // 调用目标方法
        DecisionFlowServiceImpl spy = PowerMockito.spy(decisionFlowService);
        PowerMockito.when(spy, "getUserGroupDynamicSql", "城市", 1).thenReturn(Lists.newArrayList());
    }

}

4. 断点测试执行情况

        在目标方法打断点, 查看单元测试的执行情况

        首先观察使用了 @InjectMocks 注解声明的字段, 可以看到是实例对象, 在这个对象里, 还注入了@Mock 帮我们生成的代理对象

Java单元测试Mock一个私有方法_junit_03

        其次是模拟数据库查询的情况, 可以看到集合里有数据, 并且都是我们在单元测试代码里自己模拟的数据, 这里我们没有建立数据库连接, 并查询数据库, 但是可以使用 mock 框架模拟查询, 拿到数据, 之后就可以对这些模拟的数据, 做之后的业务处理

Java单元测试Mock一个私有方法_Java单元测试Mock一个私有方法_04