单元测试(代码片段)

vole vole     2023-04-27     661

关键词:

一、什么是单元测试

单元测试并不只是为了验证你当前所写的代码是否存在问题,更为重要的是它可以很大程度的保障日后因业务变更、修复Bug或重构等引起的代码变更而导致(或新增)的风险。

同时将单元测试提前到编写正式代码进行(测试驱动开发),可以很好的提高对代码结构的设计。通过优先编写测试用例,可以很好的从用户角度来对功能的分解、使用过程和接口等进行设计,从而提高代码结构的高内聚、低耦合特性。使得对日后的需求变更或代码重构等更加高效、简洁。

因此编写单元测试对产品开发和维护、技术提升和积累具有重大意义!

二、为什么要进行单元测试

1、进行开发时,一定要注意代码的高内聚,低耦合性,这样也有助于单元测试的编写。

2、一个功能进行单元测试可以分为三个部分:准备数据,调用方法,验证。(展开详细说)

3、一个方法如果融合了很多的逻辑,就没有办法对某一段逻辑进行测试。这就对代码的内聚性有较高的要求。

4、一个接口的返回值,可能对我们对功能的验证并不友好,这就要求我们对这个接口内的方法进行具体的单元测试编写:

高内聚很容易做到这一点:我们可以针对这个接口功能内部的方法进行覆盖测试:不妨以这三个步骤进行测试:【1】对数据处理逻辑尽行单元测试;【2】对逻辑进行单元测试;【3】对调用的工具类进行单元测试(需要注意的是,封装而成的工具类一般都有一定的成熟度,不需要在进行单元测试的编写了)。

这样,虽然这个接口的整体返回值并不友好,我们却通过对该接口内部的每个方法,保证了功能的正确性。

其实,排除了工具类的测试,主要是针对数据处理逻辑的验证。

三、单元测试代码示例

1、Junit4 

1.1引入依赖

<properties>
  <spring.version>4.3.5.RELEASE</spring.version>
</properties>

<!--Junit4 start-->
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-mock</artifactId>
    <version>2.0.8</version><!-- 2.0 -->
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>$spring.version</version>
  </dependency>
  <dependency>
 <groupId>framework</groupId>
 <artifactId>pdfb-framework</artifactId>
 <version>1.0.0</version>
</dependency>
  <dependency>
    <groupId>mockito-core</groupId>
    <artifactId>mockito-core</artifactId>
    <version>1.10.19</version>
  </dependency>
  <!--<dependency>
    <groupId>objenesis</groupId>
    <artifactId>objenesis</artifactId>
    <version>3.0.1</version>
  </dependency>-->
  <dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>2.0.0-beta.5</version>
  </dependency>
  <dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito</artifactId>
    <version>1.6.5</version>
  </dependency>
  <dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito-common</artifactId>
    <version>1.6.5</version>
  </dependency>

  <dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-support</artifactId>
    <version>2.0.0-beta.5</version>
  </dependency>

  <dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-core</artifactId>
    <version>2.0.0-beta.5</version>
  </dependency>

  <dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4-common</artifactId>
    <version>2.0.0-beta.5</version>
  </dependency>

  <dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-reflect</artifactId>
    <version>2.0.0-beta.5</version>
  </dependency>
  <!--Junit4 end-->

1.2 样例一:访问数据库

本样例是应用的ssm框架,需要添加
@RunWith(SpringJUnit4ClassRunner.class)的注解,才能调用Spring容器。
注解
@ContextConfiguration(locations = "classpath:spring/applicationContext.xml")
的作用是访问Spring的配置文件。
package com.asd.modules.service.impl;

import com.asd.common.shiro.util.StringUtils;
import com.asd.common.utils.TestUtils;
import com.asd.common.utils.time.DateUtils;
import com.asd.modules.dao.IBNRExportMapper;
import com.asd.modules.dao.TAssessTreatyMapper;
import com.asd.modules.pojo.currencybreak.model.CurrencyBreak;
import com.asd.modules.service.CommonService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.math.BigDecimal;
import java.util.*;

/**
 * @author zs
 * @date 2019/5/26 9:57
 * @Description 测试偿付能力外币准备金拆分结果全部导出功能
 */

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring/applicationContext.xml")
public class CurrencyBreakServiceImplTest 

    @Autowired
    private IBNRExportMapper ibnrExportMapper;

    @Autowired
    private TAssessTreatyMapper tAssessTreatyMapper;

    @Autowired
    private CommonService commonService;

    CurrencyBreakServiceImpl currencyBreakServiceImpl = new CurrencyBreakServiceImpl();

    /**
     *@Author: zs on 2019/5/26 10:02
     *@param: []
     *@return: void
     *@Description:测试比例合约未到期--毛数据
     */
    @Test
    public void testTAssessTreatyMapper() throws Exception 

        //创建比例合约未到期--毛数据集合用于验证查询结果
        Map<String,BigDecimal> assessDate_true = new HashMap<>();
        assessDate_true.put("HKD",new BigDecimal(0.8523100000+9275116.801640+10882327.793455));
        assessDate_true.put("AUD",new BigDecimal(4.7802000000+88988.727791+18616.109742));
        assessDate_true.put("VND",new BigDecimal(0.0002884000+106447.623658+369097169.410541));
        assessDate_true.put("JPY",new BigDecimal(0.0603210000+495999.744668+8222671.120638));
        assessDate_true.put("DKK",new BigDecimal(1.0199000000+21.208229+20.794420));
        assessDate_true.put("XOF",new BigDecimal(0.0116000000+1353.861510+116712.199138));
        assessDate_true.put("CAD",new BigDecimal(5.0882000000+375383.884451+73775.379201));
        assessDate_true.put("CHF",new BigDecimal(6.6841000000+1493.033675+223.370936));
        assessDate_true.put("EUR",new BigDecimal(7.6082000000+10727578.819760+1410002.210741));
        assessDate_true.put("LAK",new BigDecimal(0.0007795000+58.003429+74411.069917));
        assessDate_true.put("USD",new BigDecimal(6.6901000000+163962755.269204+24508266.732815));
        assessDate_true.put("MOP",new BigDecimal(0.8276000000+649.709801+785.052925));
        assessDate_true.put("GBP",new BigDecimal(8.9057000000+18424172.235436+2068806.745729));

        //查询未到期数据
        Date assessdate = DateUtils.strToDate("2019-03-31");
        List<CurrencyBreak> currencyBreakList_base = tAssessTreatyMapper.searchDataByCurrency(assessdate, false, null, null, null, null);
        //比较数据是否一致
        Assert.assertEquals(assessDate_true.size(),currencyBreakList_base.size());
        //遍历数据
        for (CurrencyBreak currency: currencyBreakList_base) 
            //得到正确的值
            BigDecimal date_true = assessDate_true.get(currency.getCurrency()).setScale(6,BigDecimal.ROUND_HALF_UP);
            //得到查询的值
            BigDecimal date_base = currency.getExchrate().add(currency.getAssessCurrency()).add(currency.getAssessAccCurrency()).setScale(6,BigDecimal.ROUND_HALF_UP);
            //比较元素是否一样
            Assert.assertEquals(currency.getCurrency() + ":" + date_true,currency.getCurrency() + ":" + date_base);
        

    

1.3 样例2:利用mock工具,模拟测试数据,并不访问数据库。

需要注意的是:由于service类没有get()与set()方法,这里需要在测试前,对serviceimpl的Mapper属性赋值。

测试用工具类

//测试用公共方法
package com.asd.common.utils;

import org.apache.poi.ss.usermodel.Workbook;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

public class TestUtils 

    /**
     * 给controllerTest类setservice属性
     * @param mycontroller
     * @param myService
     * @param serviceName
     */
    public static void setService(Object mycontroller, Object[] myService, String[] serviceName)
        for(int i = 0;i < myService.length; i ++)
            try 
                Field f = mycontroller.getClass().getDeclaredField(serviceName[i]);
                f.setAccessible(true);
                f.set(mycontroller, myService[i]);
            catch (Exception e)
                e.printStackTrace();
            
        
    

    /**
     * 测试私有方法工具
     * @param objectService
     * @param methodName
     * @param objectArg
     * @param objectArgs
     * @return
     * @throws Exception
     */
    public static Object testPrivateMethod(Object objectService, String methodName,Object objectArg, Object... objectArgs) throws Exception 
        // 获取可变参数数组及其长度
        Object[] clone = objectArgs.clone();
        int length = clone.length;
        // 目前以私有方法最多传5个参数处理,count为参数的数量
        int count = 0;
        for(int i = 0; i < 5; i ++)
            if (i == length)
                count = i;
        
        Class serviceClass = objectService.getClass();
        Class<?> objectArgClass = objectArg.getClass();
        // 获取集合接口class 穷举法
        objectArgClass = getCollectionClass(objectArgClass);

        Method method;
        // 穷举出所有可变参数class
        switch (count)
            case 0 :
                // 通过反射获取当前service私有方法
                method = serviceClass.getDeclaredMethod(methodName, objectArgClass);
                // 设置私有属性可访问
                method.setAccessible(true);
                // 反射执行方法
                return method.invoke(objectService,objectArg);
            case 1 :
                Class<?> argsClass1 = clone[0].getClass();
                argsClass1 = getCollectionClass(argsClass1);
                method = serviceClass.getDeclaredMethod(methodName, objectArgClass, argsClass1);
                method.setAccessible(true);
                return method.invoke(objectService,objectArg,clone[0]);
            case 2 :
                Class<?> argsClass11 = clone[0].getClass();
                argsClass11 = getCollectionClass(argsClass11);
                Class<?> argsClass2 = clone[1].getClass();
                argsClass2 = getCollectionClass(argsClass2);
                method = serviceClass.getDeclaredMethod(methodName, objectArgClass, argsClass11,argsClass2);
                method.setAccessible(true);
                return method.invoke(objectService,objectArg,clone[0],clone[1]);
            case 3 :
                Class<?> argsClass111 = clone[0].getClass();
                argsClass111 = getCollectionClass(argsClass111);
                Class<?> argsClass22 = clone[1].getClass();
                argsClass22 = getCollectionClass(argsClass22);
                Class<?> argsClass3 = clone[2].getClass();
                argsClass3 = getCollectionClass(argsClass3);
                method = serviceClass.getDeclaredMethod(methodName, objectArgClass, argsClass111,argsClass22,argsClass3);
                method.setAccessible(true);
                return method.invoke(objectService,objectArg,clone[0],clone[1],clone[2]);
            case 4 :
                Class<?> argsClass1111 = clone[0].getClass();
                argsClass1111 = getCollectionClass(argsClass1111);
                Class<?> argsClass222 = clone[1].getClass();
                argsClass222 = getCollectionClass(argsClass222);
                Class<?> argsClass33 = clone[2].getClass();
                argsClass33 = getCollectionClass(argsClass33);
                Class<?> argsClass4 = clone[3].getClass();
                argsClass4 = getCollectionClass(argsClass4);
                method = serviceClass.getDeclaredMethod(methodName, objectArgClass, argsClass1111,argsClass222,argsClass33,argsClass4);
                method.setAccessible(true);
                return method.invoke(objectService,objectArg,clone[0],clone[1],clone[2],clone[3]);
        
        return null;
    

    // 获取集合定义class
    public static Class<?> getCollectionClass(Class<?> objectArgClass) 
        String className = objectArgClass.getName();
        switch (className) 
            case "java.util.ArrayList" :
                objectArgClass = List.class;
                break;
            case "java.util.HashMap" :
                objectArgClass = Map.class;
                break;
            case "org.apache.poi.hssf.usermodel.HSSFWorkbook" :
                objectArgClass = Workbook.class;
                break;
            case "org.apache.poi.xssf.usermodel.XSSFWorkbook" :
                objectArgClass = Workbook.class;
                break;
        
        return objectArgClass;
    

测试样例

//测试样例
package com.asd.modules.service.impl;

import com.asd.common.utils.TestUtils;
import com.asd.common.utils.time.DateUtils;
import com.asd.modules.dao.*;
import com.asd.modules.pojo.currencybreak.model.CurrencyBreak;
import com.asd.modules.service.CommonService;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

import java.math.BigDecimal;
import java.util.*;

import static org.mockito.Mockito.when;

/**
 * @author zs
 * @date 2019/5/27 11:04
 */
public class CurrencyBreakServiceImplMockTest 

    @Rule
    public MockitoRule rule = MockitoJUnit.rule();
    @Mock private TAssessTreatyMapper tAssessTreatyMapper;
    @Mock private TAssessSuptreatyMapper tAssessSuptreatyMapper;
    @Mock private TAssessFacMapper tAssessFacMapper;
    @Mock private TAssessSupfacMapper tAssessSupfacMapper;
    @Mock private IBNRExportMapper ibnrExportMapper;
    @Mock private CommonService commonService;
    CurrencyBreakServiceImpl currencyBreakService = new CurrencyBreakServiceImpl();

    @Before
    public void test()
        Object[] serviceArr = tAssessTreatyMapper,tAssessSuptreatyMapper,tAssessFacMapper,tAssessSupfacMapper,ibnrExportMapper,commonService;
        String[] stringArr = "tAssessTreatyMapper","tAssessSuptreatyMapper","tAssessFacMapper","tAssessSupfacMapper","ibnrExportMapper","commonService";
        TestUtils.setService(currencyBreakService, serviceArr,stringArr);
    

    @Test
    public void testGenIPCurrencyBreak()
        //数据库:未到期:6.6901000000 163962755.269204   24508266.732815  6.7286000000  164906323.538419
        //数据库:未决:6.6901000000  383428556.653315   57312828.904398  6.7286000000  385635100.566132
        //查询数据库中的数据
        Date date = DateUtils.strToDate("2019-03-31");
        //创建正确数据集
        List<CurrencyBreak> currencyBreak_assessList_true = new ArrayList<>();
        List<CurrencyBreak> currencyBreak_outstandingList_true = new ArrayList<>();
        //未到期数据
        CurrencyBreak currencyBreak_assess_true = new CurrencyBreak();
        currencyBreak_assess_true.setCurrency("USD");
        currencyBreak_assess_true.setExchrate(new BigDecimal(6.6901000000));
        currencyBreak_assess_true.setAssessCurrency(new BigDecimal(163962755.269204));
        currencyBreak_assess_true.setAssessAccCurrency(new BigDecimal(24508266.732815));
        currencyBreak_assessList_true.add(currencyBreak_assess_true);
        //未决数据
        CurrencyBreak currencyBreak_outstanding_true = new CurrencyBreak();
        currencyBreak_outstanding_true.setCurrency("USD");
        //currencyBreak_outstanding_true.setExchrate(new BigDecimal(6.6901000000));
        currencyBreak_outstanding_true.setOutstandingCurrency(new BigDecimal(383428556.653315));
        //currencyBreak_outstanding_true.setOutstandingAcccurrency(new BigDecimal(57312828.904398));
        currencyBreak_outstandingList_true.add(currencyBreak_outstanding_true);
        //评估时点汇率
        //当前时点汇率
        Map<String, BigDecimal> assessdateExchrate = new HashMap<>();
        assessdateExchrate.put("USD",new BigDecimal(6.6901000000));
        //当前时点汇率
        Set<String> acccurrencykey = assessdateExchrate.keySet();
        Map<String, BigDecimal> newdateExchrate = new HashMap<>();
        newdateExchrate.put("USD",new BigDecimal(6.7286000000));
        when(tAssessTreatyMapper.searchDataByCurrency(date,false,null,null,null,null)).thenReturn(currencyBreak_assessList_true);
        when(ibnrExportMapper.searchDataByCurrency(date,false,null,null,null,null)).thenReturn(currencyBreak_outstandingList_true);
        when(commonService.getAssessdateExchrate(date)).thenReturn(assessdateExchrate);
        when(commonService.getNewExchrate(acccurrencykey)).thenReturn(newdateExchrate);
        List<CurrencyBreak> currencyBreakList_base = currencyBreakService.genIPCurrencyBreak(date, false, null, null, null, null);
        //比较USD的数据
        for (CurrencyBreak currencyBreak_base : currencyBreakList_base) 
            if ("USD".equals(currencyBreak_base.getCurrency())) 
                Assert.assertEquals(new BigDecimal(164906323.538419).setScale(6,BigDecimal.ROUND_HALF_UP),currencyBreak_base.getAssessNewCurrency());
                Assert.assertEquals(new BigDecimal(385635100.566132).setScale(6,BigDecimal.ROUND_HALF_UP),currencyBreak_base.getOutstandingNewCurrency());
            
        
    

2、TestNG

2.1引入依赖

<!--TestNG begin-->
    <!--TestNG-->
    <dependency>
      <groupId>org.testng</groupId>
      <artifactId>testng</artifactId>
      <version>6.14.3</version>
      <scope>test</scope>
    </dependency>
    <!--JMockit-->
    <dependency>
      <groupId>org.jmockit</groupId>
      <artifactId>jmockit</artifactId>
      <version>1.46</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.jmockit</groupId>
      <artifactId>jmockit-coverage</artifactId>
      <version>1.23</version>
      <scope>test</scope>
    </dependency>
    <!--Spring Test-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>$spring.version</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.kubek2k</groupId>
      <artifactId>springockito</artifactId>
      <version>1.0.9</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.kubek2k</groupId>
      <artifactId>springockito-annotations</artifactId>
      <version>1.0.9</version>
      <scope>test</scope>
    </dependency>
      <!--<dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-servlet-api</artifactId>
        <version>$tomcat.servlet.api.version</version>
        <scope>test</scope>
      </dependency>-->

    <!--TestNG end-->

2.2、样例1:访问数据库。

package com.germa.service;

import com.germa.domain.Forum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests;
import org.testng.annotations.Test;


@ContextConfiguration("classpath:applicationContext-mybatis.xml")
@Rollback(false)
public class TestMyBatis extends
        AbstractTransactionalTestNGSpringContextTests 

    private ForumService forumService;
    @Autowired
    public void setForumService(ForumService forumService) 
        this.forumService = forumService;
    

    @Test
    public void testAddForum()
        //ApplicationContext ctx=new ClassPathXmlApplicationContext("classpath:applicationContext-mybatis.xml");
       // this.forumService=(ForumService)ctx.getBean("forumService");
        Forum forum=new Forum();
        forum.setForumId(3);
        forum.setForumName("forum3");
        forum.setForumDesc("Desc3");
        this.forumService.addForum(forum);
    
    

注意:

  • 第一个坑:在一开始测试时我直接新建一个测试类,并给类注解@ContextConfiguration("classpath:applicationContext-mybatis.xml"),想通过注解自动加载配置文件,然后在直接在想要测试的方法前加了testng的@Test,一运行,报错NullPointerException,然后我试了在方法内部用ApplicationContext手动加载,结果就可以了,发现是想要的Bean没有被自动注入,网上查了一下,原来在测试类想要融入Spring环境下(注解自动加载配置文件),必须extends 一个叫AbstractTransactionalTestNGSpringContextTests的类,此时,问题得以解决。
  • 第二个坑:方法成功运行,结果却在数据库看不到相应的结果,困顿许久,看了下测试产生的信息,原来是继承AbstractTransactionalTestNGSpringContextTests在测试时会自动启动事务,自动回滚,这时,只需要给测试类注解@RollBack(false)即可。

2.32、样例2:利用mock工具进行testNG测试还没有验证成功,待更新。

参看链接:

https://blog.csdn.net/ifidieyoung/article/details/83615394

技术图片

实验单元测试(代码片段)

实验五、单元测试一、实验目的1、掌握单元测试的方法;2、学习XUnit测试原理及框架;3、学习使用测试框架进行单元测试的方法和过程。 二、实验内容与要求1、了解单元测试的原理与框架1.1单元测试原理  单元测试(uni... 查看详情

实验五单元测试(代码片段)

实验五 单元测试一、实验目的1)掌握单元测试的方法2)学习XUnit测试原理及框架;3)掌握使用测试框架进行单元测试的方法和过程。二、实验内容与要求1、了解单元测试的原理与框架 1.1单元测试原理  单元测试(unitt... 查看详情

实验五单元测试(代码片段)

实验五、单元测试一、实验目的1)掌握单元测试的方法学习XUnit测试原理及框架;3)掌握使用测试框架进行单元测试的方法和过程。二、实验内容与要求1、了解单元测试的原理与框架1.1单元测试原理单元测试(unittesting),是... 查看详情

实验五单元测试(代码片段)

一、实验目的1)掌握单元测试的方法2)学习XUnit测试原理及框架;3)掌握使用测试框架进行单元测试的方法和过程。 二、实验内容与要求1、了解单元测试的原理与框架     1.1单元测试原理  单元测... 查看详情

实验单元测试(代码片段)

一、实验目的1、掌握单元测试的方法2、学习XUnit测试原理及框架3、学习使用测试框架进行单元测试的方法和过程二、实验内容与要求1、了解单元测试的原理与框架1.1单元测试原理 单元测试,是指对软件中的最小可测试单元... 查看详情

实验五单元测试(代码片段)

一、实验目的(1)掌握单元测试的方法(2)学习XUnit测试原理及框架;(3)掌握使用测试框架进行单元测试的方法和过程。二、实验内容与要求1、了解单元测试的原理与框架1.1单元测试原理单元测试(unittesting),是指对软件中的最... 查看详情

实验五单元测试(代码片段)

一、实验目的1、掌握单元测试的方法;2、学习XUnit测试原理及框架;3、学习使用测试框架进行单元测试的方法和过程。 二、实验内容与要求了解单元测试的原理与框架1.1单元测试原理     单元测试(unittes... 查看详情

单元测试(代码片段)

单元测试中,所谓单元是如何划分单元测试的对象通常是软件设计的最小逻辑单元,单元的划分在面向过程的结构化程序中一般是函数或子过程,在面向对象的程序中可以是类或类的成员函数。软件开发中,为何要进行单元测试... 查看详情

实验五单元测试(代码片段)

一、实验目的1、掌握单元测试的方法2、学习XUnit测试原理及框架3、学习使用测试框架进行单元测试的方法和过程二、实验内容与要求1、了解单元测试的原理与框架1.1单元测试原理单元测试,是指对软件中的最小可测试单元进行... 查看详情

jest单元测试入门(代码片段)

Jest单元测试入门今天,我们要讲的是Jest单元测试的入门知识。为何要进行单元测试?在学习Jest之前,我们需要回答一个问题:为何要进行单元测试?编写单元测试可以给你带来很多好处:将测试自动化,无需每次都人工测试。... 查看详情

.net单元测试的艺术&单元测试之道c#版(代码片段)

目录1.单元测试概念2.单元测试的原则3.单元测试简单示例4.单元测试框架特性标签5.单元测试中的断言Assert6.单元测试中验证预期的异常7.单元测试中针对状态的间接测试8.单元测试在MVC模式中的实现8.单元测试相关参考9.示例源代... 查看详情

javascript单元测试(代码片段)

查看详情

markdown单元测试(代码片段)

查看详情

markdown单元测试(代码片段)

查看详情

javascript单元测试(代码片段)

查看详情

csharp单元测试(代码片段)

查看详情

php单元测试(代码片段)

查看详情

texttodopythonunittest单元测试(代码片段)

查看详情