在生前一定要做完想做的事!

发布新日志

  • 接上篇单元测试

    2008-10-20 13:58:12


    l
    待测试对象及辅助对象在@Before方法中初始化。
    l全局资源可以在@BeforeClass方法中初始化。
    l全局资源通常启动缓慢,如数据库,Web服务器,放入@BeforeClass使之仅初始化一次加快测试速度。
    l要测试一个方法应当编写多个测试方法,每个测试方法各有侧重。
    l测试方法要覆盖所有可能抛出异常的情况
    当遇到错误,最好的分析步骤是
    l检查环境。
    数据库链接,数据库中的数据是否正常?配置是否正常?网络是否正常?
    l检查测试代码。
    参数是否传错误?断言的预期值是否错误?
    l检查程序。
    debug
    接口:
    public interface ICalculatorService{
    /**
     * 计算器中加法功能的计算
     * @return 参数 a,b的和
     */
    public double add(double a,double b);
    }
    实现:
    public class CalculatorService implements ICalculatorService{
    public double add(double a, double b){
    return a+b;
    }
    }
    基类:
    Public class BaseCase{
    ICalculatorService calculotorService;
    Public BaseCase(){
    calculatorService = new CalculatorService();
    }
    }
    public class AddTest extends BaseCase{
    @BeforeClass
     public static void beforeClass() {}
    @AfterClass
     public static void afterClass(){}
    @Before
    public void before() {}
    @After
     public void after(){}
    /**
     * 测试输入为0的情况
     * 预期值为0
     */
    @Test
     public void testZero(){
    double result = calculatorService.add(0,0); Assert.assertEquals(0,result);
    }
    }
    例如组合测试计算器中的加减乘除的测试方法
    import org.junit.runner.RunWith;
     import org.junit.runners.Suite;
     import org.junit.runners.Suite.SuiteClasses;
     @RunWith(Suite.class)
     @SuiteClasses(value = { AddTest.class })
     @SuiteClasses(value = { MinusTest.class })
     @SuiteClasses(value = { MultiplyTest.class })
     @SuiteClasses(value = { divideTest.class })
     public class AllTests {
     }
    lpublic class BaseCase {
    // 获取日志对象,并提供给它该类的日志信息
    protected final Logger log = LoggerFactory.getLogger(this.getClass());
    //初始化要测试的接口
     protected static RefundCommonAO refundCommonAO;
    //初始化要测试的接口
    protected static RefundFlowAO refundFlowAO;
    //声明数据库链接文件
    protected static String DB_PROPERITY = "db.properties";
    //声明JdbcTemplate以便对数据库进行操作
    protected static JdbcTemplate jdbcTemplate;
    l//获取spring类路径相关上下文的引用
    lstatic{
    lApplicationContext context = new ClassPathXmlApplicationContext(new String[]{
    l"biz-manager.xml",
    l"spring-persistence.xml",
    l"spring-refund-dao.xml",
    l"spring-refund-payway.xml",
    l"spring-refund-process.xml",
    l"spring-refund-service.xml",
    l"tc-client.xml",
    l"config_currect.xml",
    l"spring-refund-ao.xml"
    l});
    l//从上下文中获取被测试接口的引用。
    lrefundCommonAO = (RefundCommonAO)context.getBean("refundCommonAO");
    l
    l//从上下文中获取被测试接口的引用。
    lrefundFlowAO = (RefundFlowAO)context.getBean("refundFlowAO");
    l
    l//从上下文中获取jdbcTemplete的引用,以便对数据库进行操作
    ljdbcTemplate = (JdbcTemplate)context.getBean("jdbcTemplate");}
    l}
    l//如果测试的接口需要有数据源,那么需要调用此方法,把在excel里准备的测试数据添加到DB_PROPERITY中所定义的数据库中。
    public static void createTestData(String fileName) throws Exception{
    URL excelUrl = BaseCase.class.getClassLoader().getResource(fileName);
    URL dbUrl = BaseCase.class.getClassLoader().getResource(DB_PROPERITY);
    DataGenerator.tearDown(new String[]{excelUrl.getFile()}, dbUrl.getFile());
    DataGenerator.setUp(new String[]{excelUrl.getFile()}, dbUrl.getFile());
    l}
    l//调用此方法,删除调用createTestData添加的数据。以清理测试产生的垃圾数据。
    public static void deleteTestData(String fileName) throws Exception{
    URL excelUrl = BaseCase.class.getClassLoader().getResource(fileName);
    URL dbUrl = BaseCase.class.getClassLoader().getResource(DB_PROPERITY);
    DataGenerator.tearDown(new String[]{excelUrl.getFile()}, dbUrl.getFile());
    }
    l
    l//在测试类中可以调用此方法对数据库进行操作
    public void operaterData(String sql){
    jdbcTemplate.execute(sql);
    }
    public class QueryInfoByActionTest extends BaseCase{
    RefundInfoQuery query;
     //退款id 6000002
    private final static long PARAM = InstanceClass.REFUND_ID_6000002;
    /**
     * 调用BaseCasecreateTestData在数据库中添加excel中已准备好的测试数据。
           * instanceClass.INIT_DATA_SOURCE =  excel文件名
     */
    @BeforeClass
    public static void createTestData() throws Exception{
    createTestData(InstanceClass.INIT_DATA_SOURCE);
    }
    //在所有的测试方法都执行之后,清理createTestData保存进数据库中的数据
    @AfterClass
    public static void deleteTestData() throws Exception{
    deleteTestData(InstanceClass.INIT_DATA_SOURCE);
    }
    //在每个测试方法运行之前,执行此方法。这里是用来准备测试参数的。
    @Before
    public void before(){
    query = new RefundInfoQuery();
    query.setAction(RefundConstants.VIEW_REFUND_DETAIL); //查看退款详情
    query.setBizOrderId(PARAM);
    query.setRefundId(PARAM);
    query.setUserNumId(1234);
    l
    }
    /**
     * 查看输入参数在数据库中不存在时的返回值
     * 预期success = false; resultCode = NO_REFUND_RECORD
    *  说明:InstanceClass.DELETE_REFUND_BY_ID = "delete from tc_refund_trade t where t.REFUND_ID = ";
    *  说明:long InstanceClass.REFUND_ID_60159864 =  60159864 (REFUND_ID的值)
     */
    @Test
    public void  testRefundIsNotExit(){
      long param = InstanceClass.REFUND_ID_60159864;
      super.operaterData(InstanceClass.DELETE_REFUND_BY_ID + param ); //删除退款表中refundID60159864的数据
    query.setRefundId(param);  //把已删除掉的refundId传到参数中进行查询
    ResultSupport result = refundCommonAO.queryInfoByAction(query); //调用被测方法把参数传进去
    //以下为断言:检查返回值与预期值是否相等
    Assert.assertFalse(result.isSuccess());
    Assert.assertEquals(RefundResultCode.NO_REFUND_RECORD, result.getResultCode());
    }
    }


  • 单元测试junit初学

    2008-10-20 11:50:08



    l
    一 实例
    目前
    junit测试为接口中的方法。根据javadoc中的文字说明编写junit测试方法。
    l接口:
    lpublic interface ICalculatorService{
    /**
     * 计算器中加法功能的计算
     * @return 参数 a,b的和
     */
    public double add(double a,double b);
    }
    l实现:
    lpublic class CalculatorService implements ICalculatorService{
    public double add(double a, double b){
    return a+b;
    }
    }
    二 步骤
    l第一步: 编写一个基类以创建测试环境(可选)。
    l第二步: 编写测试类。
    l第三步: 在该测试类中编写测试方法。
    l第四步: 在测试方法中调用被测方法。
    l第五步: 验证预期结果与返回的结果是否一致。
    l第六步: 执行测试 查看测试结果。
    lTestSuite来组合测试。
    三 各步骤详解
    l第一步: 编写一个基类以创建测试环境(可选)。
    l此类会调用系统启动时的配置文件,模拟系统启动。也可以获取目标接口实现类的引用和编写测试代码时需要的公用方法。测试类的实现都需要继承此基类。
    l
    l例如如果计算机服务器有加减乘除等方法,我们可以把接口的引用放入基类,以方便各测试类调用。
    lPublic class BaseCase{
    ICalculatorService calculotorService;
    Public BaseCase(){
    calculatorService = new CalculatorService();
    }
    }
    l第二步:编写测试类。
    如果有基类要继承此基类完成测试环境的初始化。
    l通常情况下为接口中的每个方法编写一个测试类。
    l测试类的名字推荐为 被测方法名 + Test
    l例如,测试计算器中加法功能的测试类为:
    lpublic class AddTest  extends BaseCase{…}
    l第三步:在该测试类中编写测试方法。
    l(可选)编写初始化和清理方法,并标注为:@Before@After
    l@Before
         public void before() {}
    l@After
         public void after(){}
    l(可选)编写全局化初始化和清理方法,并标注为:@BeforeClassAfterClass
    l@BeforeClass
         public static void beforeClass() {}
    l@AfterClass
         public static void afterClass() {}
    l编写一个或多个测试方法,标注为@Test
    l推荐测试方法名字为 test + 测试点,如以下方法为测试计算器加法功能中输入为0的情况。
    §@Test
         public void testZero(){...}
    l第四步:在测试方法中调用接口中要测试的方法。
    l可以在BaseCase中已经引用了目标接口的实现类。在测试方法中可直接调用。也可以在测试类中直接引用目标接口的实现类。
    l例如引用计算器类中实现加法功能的add()方法。参数为两个加数。
    l@Test
      public void testZero(){
         double result = calculatorService.add(0,0);
      }
    l第五步:使用Assert所提供的静态方法验证方法调用返回的结果。
    lAssert超类所提供的核心方法如下:
    lassertEquals
    §断言两个对象相等,若不满足,方法抛出带有相应信息的AssertionFailedError异常。
    §例如计算器加法功能的测试可以使用一下验证:
    §Assert.assertEquals(0,result);
    lassertSame
    §断言两个引用指向同一个对象,若不满足,方法抛出带有相应信息的AssertionFailedError异常。
    lassertNotSame
    §断言两个引用指向不同对象,若不满足,方法抛出带有相应信息的AssertionFailedError异常。
    lassertTrue
    §断言条件为真,若不满足,方法抛出带有相应信息的AssertionFailedError异常。
    lassertFalse
    §断言条件为假,若不满足,方法抛出带有相应信息的AssertionFailedError异常。
    lassertNull
    §断言对象为null,若不满足,方法抛出带有相应信息的AssertionFailedError异常。
    lassertNotNull
    §断言对象不为null,若不满足,方法抛出带有相应信息的AssertionFailedError异常。
    lFail
    §让测试失败,并给出指定信息。
    l测试异常需要指定期待的异常类(expected=?)
    l@Test  expected=NullPointerException.class
    l测试超时需要指定超时时间(timeOut=?)

    l第六步:执行测试 查看测试结果。
    leclipse 测试类中点右键run asjunit Test执行测试。
    l 测试结果分为一下三种。
    lPass:测试通过
    lFailure:测试失败。
    lError: 由异常引起的测试错误
    lTestSuite来组合测试。
    lTestSuite来把所有的测试类组合在一起执行。
    l如把计算器功能中的加减乘除的测试方法组合起来执行测试:
         import org.junit.runner.RunWith;
     import org.junit.runners.Suite;
     import org.junit.runners.Suite.SuiteClasses;
     @RunWith(Suite.class)
     @SuiteClasses(value = { AddTest.class })
     @SuiteClasses(value = { MinusTest.class })
     @SuiteClasses(value = { MultiplyTest.class })
          @SuiteClasses(value = { divideTest.class })
     public class AllTests {
     }
    幻灯片 15
    l确保开发人员编写的被测接口方法的javadoc详细完整。
    l必须包含的内容有:场景,输入参数,输入参数的返回结果,预期抛出的异常。
    lTC中要准备测试所需要的各种条件。
    l调用要测试的方法。
    l验证被测方法的返回值和所预期的是否一致。
    l完成后,使用@After@AfterClass方法中编写代码清理各种资源。

Open Toolbar