1. 程式人生 > >使用 Spring + Mockito+PowerMock +spring-test-dbunit+hsqldb 進行單元測試可實現100%覆蓋率

使用 Spring + Mockito+PowerMock +spring-test-dbunit+hsqldb 進行單元測試可實現100%覆蓋率

使用 Mockito 比easyMock 更簡單

使用 PowerMock 可模擬靜態、私有方法

使用spring-test-dbunit 可以實現註解方式匯入xml 到資料庫,為資料庫提供測試資料如:

@DatabaseSetup 
@DatabaseTearDown
使用hsqldb 內建資料庫,不會導致資料被誤刪或其它誤操作後導致單元測試跑不過。
具體實現
1、maven 依賴
	    <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.11</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>3.2.4.RELEASE</version>
                <scope>test</scope>
            </dependency>
			<dependency>
                <groupId>org.dbunit</groupId>
                <artifactId>dbunit</artifactId>
                <version>2.4.9</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>com.github.springtestdbunit</groupId>
                <artifactId>spring-test-dbunit</artifactId>
                <version>1.0.1</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.hsqldb</groupId>
                <artifactId>hsqldb</artifactId>
                <version>2.3.1</version>
                <scope>test</scope>
            </dependency>
			<dependency>
                <groupId>org.powermock</groupId>
                <artifactId>powermock-module-junit4-rule-agent</artifactId>
                <version>1.5.5</version>
                <scope>test</scope>
            </dependency>
			<dependency>
                <groupId>org.mockito</groupId>
                <artifactId>mockito-all</artifactId>
                <version>${mockito.version}</version>
                <scope>test</scope>
            </dependency>

            <dependency>
                <groupId>org.powermock</groupId>
                <artifactId>powermock-module-junit4</artifactId>
                <version>${powermock.version}</version>
                <scope>test</scope>
            </dependency>

            <dependency>
                <groupId>org.powermock</groupId>
                <artifactId>powermock-api-mockito</artifactId>
                <version>${powermock.version}</version>
                <scope>test</scope>
            </dependency>

2、單元測試父類BaseSpringTest
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring/bcs-spring-context-test.xml")
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, DbUnitTestExecutionListener.class })
@Transactional
public abstract class BaseSpringTest {

}


3、編寫單元測試
@PrepareForTest({ HttpClientUtil.class })//使用powermock
public class IdCardValidateServiceImplTest extends BaseSpringTest {

    @Resource
    @InjectMocks  //把被模擬物件注入
    private IdCardValidateService idCardValidateService;

    @Resource
    private AppConfig appConfig;

    @Mock //被模擬物件
    private SequenceDao sequenceDao;

    @Rule  //spring 與 powermock 組合需要使用PowerMockRule
    public PowerMockRule rule = new PowerMockRule();

    private static  final String  MOCK_RETURN_SUCC_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><result><returnCode>0000</returnCode><userCode>043101180050000</userCode><validateType>01</validateType><checkPhoto>3xf89Hoqpk0VIH/9k=</checkPhoto><traceNo>1001123</traceNo><responseDatetime>20150120154442</responseDatetime><Sign>C0AED4A3EE24D4913C71E6DBD323D1EB</Sign></result>";
   
    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        PowerMockito.mockStatic(HttpClientUtil.class);//使用powermock 模擬靜態類
    }

    //正常流程,先查庫,庫裡沒有再調介面。庫裡面沒有該身份證資訊
    @Test
    @DatabaseSetup({"classpath:/dbunit/T_BCS_IDCARD_INFO.xml",
            "classpath:/dbunit/T_BCS_PLAT.xml"})
    @DatabaseTearDown(value = {"classpath:/dbunit/T_BCS_IDCARD_INFO.xml",
            "classpath:/dbunit/T_BCS_PLAT.xml"},type = DatabaseOperation.TRUNCATE_TABLE)
    public void testValidate() throws Exception {
        String seq =RandomStringUtils.randomNumeric(7);
        Mockito.when(sequenceDao.getIdcardLogSeq()).thenReturn(Long.valueOf(seq));//Mockito模擬返回
        Mockito.when(sequenceDao.getIdcardInfoSeq()).thenReturn(Long.valueOf(seq));//Mockito模擬返回
        IdCardReq req = new IdCardReq();
        req.setReqSeq("123");
        req.setPlatCode("1001");
        req.setRequestTime(new Date());
        req.setNeedPhoto(false);
        IDCardVO idCardVO = new IDCardVO();
        idCardVO.setIdentityNo("430022198509136854");
        idCardVO.setIdentityType("00");
        idCardVO.setRealName("劉德華");
        req.setIdCard(idCardVO);
        List params = IdCardValidateServiceImpl.getParamList(req, appConfig);
		//PowerMock模擬返回
        PowerMockito.when(HttpClientUtil.doPost(appConfig.getGztUrl(),params,"UTF-8")).thenReturn(MOCK_RETURN_SUCC_XML);
        BcsResponse<IdCardRes> res =  idCardValidateService.validate(req);
        Assert.assertEquals(ErrorCodeEnum.SUCCEED_CODE.getErrorcode(),res.getErrorCode());
        Assert.assertEquals(ErrorCodeEnum.SUCCEED_CODE.getErrordesc(),res.getErrorMsg());

    }
}


用 hsqldb 時候注意

資料型別區別
oracle           hsqldb 
varchar2         varchar
number           NUMERIC 
date             TIMESTAMP


另外hsqldb獲取sequence與oracle方式不一樣,所以需要模擬