关闭

JUnit单元测试相关实验进阶

发表于:2024-2-17 09:20

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:烟雨平生9527    来源:CSDN

  一、进阶实验
  1.1Junit参数化测试
  任务描述
  根据所学内容,要求用户补全Junit的参数化测试代码。
  相关知识
  Junit参数化测试
  如果测试代码大同小异,代码结构都是相同的,不同的只是测试的数据和预期值,那么Junit的参数化测试可以派上用场了:Junit的参数化测试允许开发人员使用不同的参数反复运行同一个测试。你将遵循以下 5 个步骤来创建参数化测试。
  1. 用 @RunWith(Parameterized.class) 来注释 test 类。
  2. 创建一个由 @Parameters 注释的公共的静态方法,它返回一个对象的集合(数组)来作为测试数据集合。
  3. 创建一个公共的构造函数,它接受和一行测试数据相等同的东西。
  4. 为每一列测试数据创建一个实例变量。
  5. 用实例变量作为测试数据的来源来创建你的测试用例
  在JUnit中,可以使用@RunWith 和@parameter这两个注解来为单元测试传递参数。
  @RunWith注解:当类被@RunWith注解修饰,或者类继承了一个被该注解修饰的类,JUnit将会使用这个注解所指明的运行器(runner)来运行测试。
  @Parameters注解:然后在该类提供数据的方法上加上一个@Parameters注解,这个方法必须是静态static的,不能带参数,并且返回一个集合Collection。
  在测试类的构造方法中为各个参数赋值,(构造方法是由JUnit调用的),最后编写测试类,它会根据参数的组数来运行测试多次。
  注意:必须要为类的所有字段赋值,不管你是不是都用到!否则,Junit会出错。
  代码示例
  我们现在来看一个简单的 add 方法。
  //MathUtils.java
  package com.trustie.junittest;
  public class MathUtils {
      public static int add(int a, int b) {
          return a + b;
      }
  }
  接下来我们创建一个为上面的JUnit测试类 MathUtilsTest.java:
  //MathUtilsTest.java
  package com.trustie.junittest;
  import java.util.Arrays;
  import java.util.Collection;
  import org.junit.Assert;
  import org.junit.Test;
  import org.junit.runner.RunWith;
  import org.junit.runners.Parameterized;
  import org.junit.runners.Parameterized.Parameters;
  import com.trustie.junittest.MathUtils;
  /**
   * 参数化测试的类必须有Parameterized测试运行器修饰
   */
  @RunWith(Parameterized.class)
  public class MathUtilsTest {
      private int input1;
      private int input2;
      private int expected;
      /**
       * 准备数据。数据的准备需要在一个方法中进行,该方法需要满足一定的要求:
       * 1)该方法必须由Parameters注解修饰
       * 2)该方法必须为public static的
       * 3)该方法必须返回Collection类型
       * 4)该方法的名字不做要求
       * 5)该方法没有参数
       * @return
       * 这里设置了四组参数,只有当四组参数都通过测试,才代表测试通过
       */
      @Parameters
      public static Collection prepareData(){
          Object [][] bject = {{-1,-2,-3},{0,2,2},{-1,1,0},{1,2,3}};
          return Arrays.asList(bject);
      }
      
      public MathUtilsTest(int input1,int input2,int expected){
          this.input1 = input1;
          this.input2 = input2;
          this.expected = expected;
      }
      @Test
      public void testAdd(){
          MathUtils add = new MathUtils();
          int result = add.add(input1, input2);
          Assert.assertEquals(expected,result);
      }
  }
  编程要求
  给定一个减法函数Calculator.java如下:
  Calculator.java
    
  /** 
   * 数学计算-->减法 
   */  
  public class Calculator {  
      public int sub(int a, int b) {  
          return a - b;  
      }  
  }
  请按照上面索索的知识,补全题目中参数化测试 ParameterTest.java 的prepareData()函数。
  本关涉及的代码文件ParameterTest.java的代码如下:
  评测说明
  本关卡的测试文件是TestRunner.java,该文件进行了函数封装且学员不可见,用于验证学员的Junit测试代码是否正确。
  具体测试过程如下:
  1.平台自动编译生成TestRunner.exe;
  2.平台运行TestRunner.exe;
  3.获取TestRunner.exe输出,并将其输出与预期输出对比:如果一致则测试通过,否则测试失败。
  预期输入: 预期输出:true
  package step1;
   
  import static org.junit.Assert.assertEquals; //静态导入
  import java.util.Arrays;
  import java.util.Collection;
  import org.junit.Test;
  import org.junit.runner.RunWith;
  import org.junit.runners.Parameterized;
  import org.junit.runners.Parameterized.Parameters;
  import step1.Calculator;
  /**
   * JUnit4的参数化测试
   */
  @RunWith(Parameterized.class)
  public class ParameterTest {
      private int input11;
      private int input22;
      private int expected;
      public ParameterTest(int input11, int input22, int expected){
          this.input11 = input11;
          this.input22 = input22;
          this.expected = expected;
      }
   
      @Parameters
      public static Collection prepareData(){
          /**
           *该二维数组的类型必须是Object类型的
           *该二维数组中的数据是为测试Calculator中的sub()方法而准备的
           *该二维数组中的每一个元素中的数据都对应着构造方法ParameterTest()中的参数的位置
           *所以依据构造方法的参数位置判断,该二维数组中的第一个数减去第二个数等于第三个数
           *请在Begin/End内补全代码,要求为单元测试传递4组参数,来验证Calculator中的sub函数编写是否正确
           *提示:只需要补2行代码
           */
          /*********************************Begin*************************************************/
          return Arrays.asList(new Object[][] {
              {5, 3, 2},
              {10, 5, 5},
              {8, 4, 4},
              {15, 7, 8}
          });
   
          /**********************************End**************************************************/
   
      }
      @Test
      public void testSub(){
          Calculator cal = new Calculator();
          assertEquals(cal.sub(input11, input22), expected);
      }
  }
  1.2Junit异常测试
  任务描述
  学员写一个Junit异常测试,用来判断实例化的对象数据是否合法。
  相关知识
  Junit异常测试
  Junit 用代码处理提供了一个追踪异常的选项。你可以测试代码是否它抛出了想要得到的异常。通过@Test元数据中的expected属性验证是否抛出期望的异常,expected属性的值是一个异常的类型,如果抛出了期望的异常,则测试通过,否则不通过。
  现在让我们看下 @Test(expected=* .class)注解的具体使用。
  代码示例
  // ExceptionTest.java
  public class ExceptionTest {
     
      @Test(expected = ArithmeticException.class)  // 使用@Test注解,期望抛出ArithmeticException异常
      public void divisionWithException() {  
        int i = 1/0; // 除数为0,将抛出ArithmeticException异常
      }  
      
  }
  在上述例子中,divisionWithException()方法将抛出ArithmeticException异常,因为这是一个预期的异常,因此单元测试会通过。其实,Junit的异常测试我们追踪到了预期的异常信息,所以代码会执行成功而不是中断。
  编程要求
  本关的任务是写一个Junit异常测试,用来判断实例化的对象数据是否合法。具体在JunitException.java中补全异常测试代码:要求判断Person类中实例化的对象年龄是否合法,如果不合法则抛出IllegalArgumentException异常。
  Person类代码如下:
  // 定义一个Person类
  public class Person {
      // 定义私有变量name,表示人的姓名
      private String name;
      // 定义私有变量age,表示人的年龄
      private int age;
   
      // 定义公共方法getName,用于获取当前对象的姓名
      public String getName() {
          return name;
      }
   
      // 定义公共方法setName,用于设置当前对象的姓名
      public void setName(String name) {
          this.name = name;
      }
   
      // 定义公共方法getAge,用于获取当前对象的年龄
      public int getAge() {
          return age;
      }
   
      // 定义公共方法setAge,用于设置当前对象的年龄
      public void setAge(int age) {
          // 如果传入的年龄小于0,抛出异常,提示年龄无效
          if (age < 0) {
              throw new IllegalArgumentException("age is invalid");
          }
          // 否则,将传入的年龄赋值给当前对象的age变量
          this.age = age;
      }
  }
  测试类JunitException.java的代码如下:
  评测说明
  本关卡的测试文件是TestRunner.java,该文件进行了函数封装且学员不可见,用于验证学员的Junit测试代码是否正确。
  具体测试过程如下:
  1.平台自动编译生成TestRunner.exe;
  2.平台运行TestRunner.exe; 
  3.获取TestRunner.exe输出,并将其输出与预期输出对比:如果一致则测试通过,否则测试失败。
  预期输入: 预期输出:true
  package step2;
  import static org.junit.Assert.*;
   
  import org.junit.Rule;
  import org.junit.Test;
  import org.junit.rules.ExpectedException;
  import step2.Person;
   
   
   
  public class JunitException {
   
      /**
       *请在Begin/End内加一行注解,要求检查Person对象的年龄是否合法,不合法则
       *抛出IllegalArgumentException异常
       */
      /************************************Begin**********************************************/
        @Test(expected = IllegalArgumentException.class)  
   
      /************************************End************************************************/
   
      public void checkage() {
      Person person = new Person();
      person.setAge(-1);
   
      }
  }
  1.3Junit套件测试
  任务描述
  根据所学内容,要求用户补全Junit的套件测试代码。 ####相关知识 #####本关必读
  测试套件意味着捆绑几个单元测试用例并且一起执行他们。在 JUnit 中,@RunWith 和 @Suite 注释用来运行套件测试。
  代码示例
  对下面两个类进行单元测试 ,组成套件测试。
  类代码:
  //Car.java
  public class Car {
      public int getWheels() {
          return 4;
      }
  }
   
  //Rectangle.java
  public class  Rectangle{
      public int getArea(int width,int height){
          return width*height;
      }
  }
  测试类代码:
  // CarTest.java
  public class CarTest {
      Car car; // 声明一个Car类型的变量car
   
      @Before // 使用@Before注解,表示在执行testGetWheels方法之前,会先执行setUp方法
      public void setUp() throws Exception {
          car = new Car(); // 创建一个新的Car对象,并将其赋值给car变量
      }
   
      @Test // 使用@Test注解,表示这是一个测试方法
      public void testGetWheels() {
          int result = car.getWheels(); // 调用car对象的getWheels方法,获取轮子数量,并将结果赋值给result变量
          assertEquals(4, result); // 使用断言方法assertEquals,判断result是否等于4,如果不等于4,则测试失败
      }
  }
  //RectangleTest.java
  public class RectangleTest {
      Rectangle rectangle;
      @Before
      public void setUp() throws Exception {
          rectangle=new Rectangle();
      }
      @Test
      public void testGetArea() {
          int result = rectangle.getArea(12, 2);
          assertEquals(24, result);
      }
  }
  测试套件代码:
  @RunWith(Suite.class)
  @Suite.SuiteClasses({ CalculateTest.class, CarTest.class, RectangleTest.class })
  public class AllTests {
  }
  注意:套件测试代码需要紧靠测试类,不能有换行!
  编程要求
  本关卡的要求是让学员补全Junit的套件测试代码。具体要求如下:
  给定一个类Calculate.java和对应的测试类CalculateTest.java,如下:
  //Calculate.java
  public class Calculate {
      public int add(int a, int b) {
          return a + b;
      }
  }
  //CalculateTest.java
  public class CalculateTest {
      Calculate calculate;
      @Before
      public void setUp() throws Exception {
          calculate = new Calculate();
      }
      @Test
      public void testAdd() {
          int result = calculate.add(12, 12);
          assertEquals(24, result);
      }
  }
  请在SuiteTest.java内补全CalculateTest和CarTest的套件测试代码。
  本关涉及到的SuiteTest.java代码如下:
  评测说明
  本关卡的测试文件是TestRunner.java,该文件进行了函数封装且学员不可见,用于验证学员的Junit测试代码是否正确。
  具体测试过程如下:
  1.平台自动编译生成TestRunner.exe; 2.平台运行TestRunner.exe; 3.获取TestRunner.exe输出,并将其输出与预期输出对比:如果一致则测试通过,否则测试失败。
  预期输入: 预期输出:true
  package step3;
   
  import static org.junit.Assert.*;
   
  import org.junit.Test;
  import org.junit.runner.RunWith;
  import org.junit.runners.Suite;
  import step3.Calculate;
  import step3.CalculateTest;
  import step3.Car;
  import step3.CarTest;
   
  /*
  请在星号后加两行注解,要求实现CalculateTest类和CarTest类的套件测试
  套件测试代码需要紧靠SuiteTest这个类,不能有换行
  */
  /**************************************************************
   * 使用Suite类进行测试套件的创建
   * @RunWith(Suite.class) 表示使用Suite类作为测试运行器
   * @Suite.SuiteClasses({ CalculateTest.class, CarTest.class }) 表示将CalculateTest类和CarTest类添加到测试套件中
   */
  @RunWith(Suite.class)
  @Suite.SuiteClasses({ CalculateTest.class, CarTest.class })
  public class SuiteTest {
   
  }
  1.4命令行下进行Junit测试
  任务描述
  补全TestRunner.java中的代码,如果测试类JunitSubTest.java中的测试都通过,则main函数会打印true。
  环境配置
  环境配置:Linux主机+JDK 1.8+Junit 4.12。
  首先确保自己在linux主机装好了java环境,配置好环境变量。
  然后下载两个jar包:
  junit 4.12 :Release JUnit 4.12 · junit-team/junit4 · GitHub
  hamcrest-core-1.3.jar : http://central.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar
  让后把这两个包放到jdk安装的lib目录下,本机的JDK安装目录如下:
  /home/soft/jdk1.8.0_111/lib# ls
  amd64           hamcrest-core-1.3.jar  jexec           packager.jar
  ant-javafx.jar  ir.idl                 junit-4.12.jar  sa-jdi.jar
  ct.sym          javafx-mx.jar          missioncontrol  tools.jar
  dt.jar          jconsole.jar           orb.idl  
  然后修改本机环境变量:
  vim ~/.bashrc 
  修改成如下:
  export JAVA_HOME=/home/soft/jdk1.8.0_111
  export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/junit-4.12.jar:$JAVA_HOME/lib/hamcrest-core-1.3.jar:$CLASSPATH
  export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH:$HOME/bin
  这里着重看下CLASSPATH,JAVA_HOME和PATH如果设置过,就不用修改了。
  然后source ~/.bashrc 让环境变量生效。
  新建两个java文件:Calculate.java和CalculateTest.java。
  //Calculate.java
  package com.trustie.junitest;
  public class Calculate {
      public int sum(int var1, int var2) {
          System.out.println("相加的值是: " + var1 + " + " + var2);
          return var1 + var2;
      }
      public static void main(String[] args) {
          System.out.println("hh");  
      }
  }
  //CalculateTest.java
  package com.trustie.test;
  import org.junit.Test;
  import static org.junit.Assert.assertEquals;
  import org.junit.Test;
  import com.trustie.junitest.Calculate;
  public class CalculateTest {
      Calculate calculation = new Calculate();
      int sum = calculation.sum(2, 5);
      int testSum = 7;
      @Test
      public void testSum() {
          System.out.println("@Test sum(): " + sum + " = " + testSum);
          assertEquals(sum, testSum);
      }
  }
  然后编译执行:
  javac -d . Calculate.java
  javac -d . CalculateTest.java
  java org.junit.runner.JUnitCore com.trustie.test.CalculateTest
  就可以看到如下打印:
  JUnit version 4.12
  相加的值是: 2 + 5
  .@Test sum(): 7 = 7
  Time: 0.003
  OK (1 test)
  至此,Junit环境配置成功,可以在本机命令行下运行Junit测试。
  其实在命令行中运行JUnit测试,使用了org.junit.runner.JUnitCore类。 这个类提供了runClasses()方法,它允许运行一个或多个测试类。runClasses()方法返回类型是org.junit.runner.Result对象类型。 这个对象可以被用来收集关于测试信息。此外,如果有一个失败的测试,可以用org.junit.runner.notification.Failure对象保存失败测试的描述。
  代码示例
  之前各个关卡中的TestRunner.java我们现在揭开谜底吧:
  // TestRunner.java
  import org.junit.runner.JUnitCore; // 导入JUnit核心类库
  import org.junit.runner.Result; // 导入测试结果类
  import org.junit.runner.notification.Failure; // 导入失败通知类
   
  public class TestRunner {
     public static void main(String[] args) {
        // 使用JUnitCore运行Test类的测试用例,并将结果存储在result变量中
        Result result = JUnitCore.runClasses(Test.class);
        
        // 遍历result中的所有失败用例,并打印失败信息
        for (Failure failure : result.getFailures()) {
           System.out.println(failure.toString());
        }
        
        // 打印测试是否成功的信息
        System.out.println(result.wasSuccessful());
     }
  }
  如果你的测试类Test.java中所有测试都通过,以上代码会打印true。
  本关任务
  补全TestRunner.java中的代码,如果测试类JunitSubTest.java中的测试都通过,则main函数会打印true。
  本关涉及的代码文件TestRunner.java的代码如下:
  评测说明
  本关卡的测试文件是TestRunner.java,用于验证学员的Junit测试代码是否正确。
  具体测试过程如下:
  1.平台自动编译生成TestRunner.exe; 
  2.平台运行TestRunner.exe; 
  3.获取TestRunner.exe输出,并将其输出与预期输出对比:如果一致则测试通过,否则测试失败。
  预期输入: 预期输出:true
  package step4;
   
  import org.junit.runner.JUnitCore;
  import org.junit.runner.Result;
  import org.junit.runner.notification.Failure;
   
  public class TestRunner {
     public static void main(String[] args) {
      //请在Begin/End内加一行代码,要求如果测试类JunitSubTest.java中的测试都通过,则main函数会打印true
      /******************************Begin**************************************************/
      
      // 创建一个JunitSubTest对象
      JunitSubTest junitSubTest = new JunitSubTest();
      // 使用JUnitCore运行junitSubTest类中的所有测试用例,并将结果存储在result变量中
      Result result = JUnitCore.runClasses(junitSubTest.getClass());
      
      /******************************End****************************************************/
        for (Failure failure : result.getFailures()) {
           System.out.println(failure.toString());
        }
        System.out.println(result.wasSuccessful());
     }
  }
  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号