• JUnit4在Eclipse中的使用


    测试是项目开发中很重要的一环。实际上,建议的项目前期编写过程是:构思-> 编写单元测试代码-> 编写接口->编写实现类-> 测试实现类->编写主类...。JUnit是一个使用广泛的、用于编写和运行可重复的测试的Java测试框架。这里不多介绍背景,直接说用法了。

    1.JUnit测试用例的创建

    首先,在pom.xml(Maven)中添加依赖:

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>

    然后,在src/test/java下的包中新建>JUnit测试用例,在下图所示界面中选择“新建JUnit4测试”(1),填写类名(2)和要测试的类(3),选择要创建的方法存根(4),点击下一步:

    这里介绍一下可选的方法存根(4):

    • setUpBeforClass():注解@BeforeClass,在运行测试类的最开始运行一次,用作测试准备(读取文件、链接数据库等)。
    • tearDownAfterClass():注解@AfterClass,在运行测试类的最后运行一次,用作测试清理(释放资源)。
    • setUp():注解@Befor,在运行每个要测试方法前运行,有多少个要测试的方法就运行多少次,用作测试方法准备。
    • tearDown():注解@After,在运行每个要测试方法后运行,有多少个要测试的方法就运行多少次,用作测试方法清理。

    最后,选择要测试的方法,点击完成:

    在生成的测试类中,会对每个选中的方法生成一个测试方法(testXxx)。如果选中了“创建终态方法存根”,则生成的测试方法都带有final修饰符;如果选中了“为生成的测试方法创建任务”,则生成的测试方法中都会出现//TODO标识。

    2.测试类的编写

    (1)JUnit4中的注解

    • @BeforeClass:该方法在所有测试方法运行之前,运行一次。方法必须是public static void。
    • @AfterClass:该方法在所有测试方法运行完毕后,运行一次。方法必须是public static void。
    • @Before:该方法在每个@Test运行之前都要运行。方法必须是public void。
    • @After:该方法在每个@Test运行之后都要运行。方法必须是public void。
    • @Test:表示该方法是测试方法。方法必须是public void。@Test可以有两个参数:expected,timeout,分别对应异常测试和超时测试。
    • @Ignore:对测试类或@Test测试方法使用,表示暂时忽略该测试。JUnit执行结果会报告忽略数量。

    通过步骤1生成的测试类,会在setUpBeforeClass、tearDownAfterClass、setUp、tearDown、testXxx方法前自动添加相应注解。

    (2)Assert类

    Assert类是JUnit中提供的一个工具类,这个类中有大量的静态方法进行断言的处理。在各测试方法中,在调用要测试的方法后,通过Assert类中的方法判断运行结果是否符合预期。

    一般为了方便使用Assert类中的静态方法,在测试类中对Assert类中的方法进行静态导入:

    import static org.junit.Assert.*;

    这里简单介绍几种Assert类中的常见方法(细节详见Assert(JUnit API)):

    • assertArrayEquals((错误信息,)预期结果数组,测试结果数组):断言测试结果数组与预期结果数组相等。如果不相等,抛出AssertionError,表示测试未通过。如果存在信息参数,则抛出带指定信息的AssertionError。
    • assertEquals((错误信息,)预期结果,测试结果):断言测试结果==预期结果。如果不相等,处理方式同上。
    • assertNotEquals((错误信息,)不期望的结果,测试结果):断言测试结果不等于不期望的结果。如果相等,处理方式同上。
    • assertNull((错误信息,)Object):断言对象为空。如果不为空,处理方式同上。
    • assertNotNull((错误信息,)Object):断言对象不为空。如果为空,处理方式同上。
    • assertSame((错误信息,)期望Object,测试Object):断言测试Object和期望Object引用了同一对象。如果引用了不同对象,处理方式同上。
    • assertNotSame((错误信息,)不期望的Object,测试Object):断言测试Object引用的不是不期望的Object。如果引用同一对象,处理方式同上。
    • assertTrue((错误信息,)boolean):断言判定条件(boolean)为true。如果为false,处理方式同上。
    • assertFalse((错误信息,)boolean):断言判定条件(boolean)为false。如果为true,处理方式同上。
    • assertThat((错误信息,)结果参数T,Matcher<? super T>):断言结果参数满足Matcher的条件。如果不满足,抛出带有Matcher和结果信息的AssertionError。如果存在信息参数,则抛出的AssertionError还带有错误信息。
    • fail((识别信息)):使测试不通过。如果存在信息参数,则为测试不通过加上识别信息。

    当比较对象为double或float时,应加上对应类型的delta参数,即:判定比较对象相等时的最大误差。

    (3)测试方法的编写

    对于每个测试方法,一般都是先调用要测试的方法,然后通过Assert中的方法,判断测试结果是否符合预期。

    对于每个要测试的方法,可以有3个测试方法:运行结果测试、异常测试、性能测试。三者的功能分别是测试指定方法运行结果是否符合预期、有问题时是否能正确抛出异常、能否在限定时间内完成运行,参数分别是@Test、@Test(expected=XxxException.class)、@Test(timeout=xxx)。可以根据实际需求,选择编写其中的1~3个测试方法。

    注意,每个test方法中最好只测试被测类中的一种方法,尽量不要在一个test方法中调用两个以上的被测方法。

    节选示例:测试向数据库添加学生信息的addStu方法和通过专业学号查询数据的query...方法。

    被测试方法:

        public StudentDAOImpl() {
            // TODO 自动生成的构造函数存根
            apc = new ClassPathXmlApplicationContext("applicationContext.xml");
            jdbcTemplate = (JdbcTemplate) apc.getBean("jdbcTemplate");
        }
    
        public boolean addStu(Student stu) {
            // TODO 自动生成的方法存根
            String name = stu.getName(), major = stu.getMajor();
            int jnshuId = stu.getJnshuId();
            if (name==null || major==null || jnshuId==0) {
                throw new RuntimeException("姓名、专业、学号不能为空!");
            }
            String sql = "INSERT INTO students (name,qq,major,entrytime,gra_school,id_jnshu"
                    + ",daily_url,desire,bro_jnshu,knowfrom) VALUES (?,?,?,?,?,?,?,?,?,?)";
            int line = jdbcTemplate.update(sql,new Object[] {
                    name,stu.getQq(),major,stu.getEntryTime(),
                    stu.getSchool(),jnshuId,stu.getDailyUrl(),stu.getDesire(),
                    stu.getJnshuBro(),stu.getKnowFrom()});
            return line>0?true:false;
        }
    
        public Student queryStuByJnshu(String major, int jnshuId) {
            // TODO 自动生成的方法存根
            String sql = "SELECT id,create_at,update_at,name,qq,major,entrytime,gra_school,id_jnshu" + 
                    ",daily_url,desire,bro_jnshu,knowfrom FROM students WHERE id_jnshu=? and major=?";
            Student stu = null;
            try {
                stu = jdbcTemplate.queryForObject(sql, new QueryStuRowMapper(),new Object[]{jnshuId,major});
            } catch (EmptyResultDataAccessException e) {
                // TODO 此处可做更复杂的提示动作,比如抛出异常、记录到本地文件、显示到GUI等。
                System.out.println("该学生不存在!");
            }
            return stu;
        }

    其中,QueryStuRowMapper代码如下:

    package cn.cage.student;
    
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import org.springframework.jdbc.core.RowMapper;
    
    public class QueryStuRowMapper implements RowMapper<Student> {
        /**
         * 直接使用此类建立的对象时,sql语句应查询Student的所有属性。*/
        public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
            // TODO 自动生成的方法存根
            Student stu = new Student(rs.getString("name"), rs.getString("major"), rs.getInt("id_jnshu"));
            stu.setId(rs.getLong("id"));
            stu.setCreateTime(rs.getLong("create_at"));
            stu.setUpdateTime(rs.getLong("update_at"));
            stu.setQq(rs.getString("qq"));
            // TODO 此处根据测试结果(时间格式)看是否需要修改
            stu.setEntryTime(rs.getDate("entrytime").toString());
            stu.setSchool(rs.getString("gra_school"));
            stu.setDailyUrl(rs.getString("daily_url"));
            stu.setDesire(rs.getString("desire"));
            stu.setJnshuBro(rs.getString("bro_jnshu"));
            stu.setKnowFrom(rs.getString("knowfrom"));
            return stu;
        }
    }

    测试方法:

        @BeforeClass
        public static void setUpBeforeClass() throws Exception {
            stuDao = new StudentDAOImpl();
        }
        
        @AfterClass
        public static void tearDownAfterClass() throws Exception {
            stuDao = null;
        }
    
        @Test
        public void testAddStu() {
            Student stu = new Student("王五", "Java后端工程师", 1470);
            assertTrue("插入失败!",stuDao.addStu(stu));
        } 
    
        @Test
        public void testQueryStuByJnshu() {
            Student stu = new Student("王五", "Java后端工程师", 1470);
            Student actual = stuDao.queryStuByJnshu("Java后端工程师", 1470);
            assertEquals("插入错误,或查询方法(byJnshu)有问题!",stu, actual);
        }

    3.运行测试

    编写完测试类和被测试类后,在测试类上右键>运行方式>JUnit测试即可。

    注意:运行测试的顺序并非是按照函数的先后顺序!如果要修改运行测试的顺序,可以在class上加注解:@FixMethodOrder(*)。可以选择的参数有:

    • MethodSorters.DEFAULT:默认顺序,不可预测但固定的顺序(每次顺序都相同)。
    • MethodSorters.JVM:测试方法执行顺序为JVM返回的顺序,不固定的顺序(每次顺序可能不同)
    • MethodSorters.NAME_ASCENDING:按测试方法名(字典顺序)升序执行。(如果是自定义顺序,推荐这种)

    虽然可以改变测试顺序,但一个好的测试类不应该依赖于测试顺序!

    示例测试结果:

     

    插入成功,但查询结果与插入值不同。

    找到原因,是Student类中没有equals函数,所以assertEquals比较的是查询结果与插入值是否引用了同一个对象。修改后测试通过。

  • 相关阅读:
    Java:类与继承(隐藏和覆盖的问题)
    Java中的static关键字解析
    面向对象(Java中普通代码块,构造代码块,静态代码块区别及代码示例)
    面向对象要点(this关键字)
    急须知道postman RSA加密的方式
    RSA加密原理
    postman获取变量
    Mysql通过cmd访问
    一个简单的postman实例
    sum(coalesce(adjust_value,prediction_value))
  • 原文地址:https://www.cnblogs.com/cage666/p/7300585.html
Copyright © 2020-2023  润新知