JAVA自动化之Junit单元测试框架详解(下)

发表于:2021-4-20 09:26

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

 作者:逍遥子    来源:CSDN

#
JUnit
分享:
  十一、Assumptions with assume 假定测试
  使用Assumptions类中的假设方法时,当假设不成立时会报错,但是测试会显示被ignore忽略执行。也就是当一个类中有多个测试方法时,其中一个假设测试方法假设失败,其他的测试方法全部成功,那么该测试类也会显示测试成功。
  假设方法适用于:在不影响测试是否成功的结果的情况下根据不同情况执行相关代码。
  public class AssumptionsTest {
  @Test
  public void testAssumTrue() {
  System.out.println("test");
  assumeTrue(3>5);
  //该方法中下面所有的代码在上面假设的条件成立后执行 //如果上述假设不成立,则会忽略执行该行下面的代码,并报错 System.out.println("assume is true!");
  }
  @Test
  public void testAssumFalse(){
  assumeFalse(3>5);
  System.out.println("assume is true!");
  }
  }
  以下语法JUnit5支持:
  @Test
  public void testAssumTrueMessage() {
  assumeTrue(3<5,
  //第二个参数为当第一个参数不成立时,输出的自定义错误信息 () -> "Aborting test: not on developer workstation");
  System.out.println("assume is true!");
  }
  @Test
  public void testAssumeTrueLambda(){
  //这个方法的第一个参数为函数式接口,无参数返回值为boolean assumeTrue(()->{
  System.out.println("in assumeTrue");
  boolean flag = false;
  return flag;
  });
  System.out.println("out assumeTrue");
  }
  @Test
  public void testAssumThat() {
  assumingThat(3>5,
  () -> {
  //与上述方法不同的是,仅当前面假设成立时,才会执行这里面的语句 //且只会影响到该lambda表达式中的代码 assertEquals(2, 2);
  });
  //此处的断言不受上述assumingThat限制,在所有情况下都会执行 System.out.println("no effect");
  assertEquals("a string", "a string");
  }
  十二、Rules 规则
  一个JUnit Rule就是一个实现了TestRule的类,用来在每个测试方法的执行前后执行一些代码。
  1、框架自带的Rule
  JUnit自带很多已经实现过好了的JUnit Rule,比如Timeout,ExpectedException等等。
  2、自定义Rule
  自定义一个Rule就是implement一个TestRule interface,实现一个叫apply()的方法。
  例:在测试方法运行之前,记录测试方法所在的类名和方法名,然后在测试方法运行之后打印出来。
  public class MethodNameExample implements TestRule {
  @Override
  public Statement apply(final Statement base, final Description description) {
  return new Statement() {
  @Override
  public void evaluate() throws Throwable {
  //base.evaluate()之前为测试方法运行之前所做操作 String className = description.getClassName();
  String methodName = description.getMethodName();
  //运行测试方法 base.evaluate();
  //base.evaluate()之后为测试方法运行之后所做操作 System.out.println("Class name: "+className +", method name: "+methodName);
  }
  };
  }
  }
  public class RuleTest2 {
  @Rule
  public MethodNameExample methodNameExample = new MethodNameExample();
  @Test
  public void addition_isCorrect() throws Exception {
  assertEquals(4, 2 + 2);
  }
  @Test
  public void mulitiplication_isCorrect() throws Exception {
  assertEquals(4, 2 * 2);
  }
  }
  十三、Theories
  在参数化测试中,我们需要给定所有具体的测试数据组。而在Theories测试中,用户只需给定了一些数据,JUnit自动利用这些数据组合出各种各种可能的组合来执行测试。
  1、内置实现
  (1)@DataPoints注解静态变量方式
  @RunWith(Theories.class)
  public class TheoryTest {
  //允许的最大误差 private static final double DELTA = 0.01;
  /*@DataPoints注解静态变量*/
  @DataPoint
  public static int ZERO = 0;
  @DataPoint
  public static int TWO = 2;
  @DataPoint
  public static int EIGHT = 8;
  //标志这个测试为Theory测试 @Theory
  public void testDivide(int dividend, int divisor) {
  //跳过除数为0的case assumeThat(divisor, not(0));
  //Calculator.divide(dividend, divisor)方法返回他们相除的结果 assertEquals(dividend / divisor, Calculator.divide(dividend, divisor), DELTA);
  System.out.println("Passed with: dividend=" + dividend + ", divisor=" + divisor);
  }
  }
  (2)@DataPoints注解静态方法方式
  @RunWith(Theories.class)
  public class TheoryTest {
  //允许的最大误差 private static final double DELTA = 0.01;
  /*@DataPoints注解一个静态方法*/
  @DataPoints
  public static int[] getTestData() {
  return new int[]{0, 2, 8};
  }
  //标志这个测试为Theory测试 @Theory
  public void testDivide(int dividend, int divisor) {
  //跳过除数为0的case assumeThat(divisor, not(0));
  //Calculator.divide(dividend, divisor)方法返回他们相除的结果 assertEquals(dividend / divisor, Calculator.divide(dividend, divisor), DELTA);
  System.out.println("Passed with: dividend=" + dividend + ", divisor=" + divisor);
  }
  }
  @DataPoint用于注解静态变量(或静态方法),表示这个变量是个数据点。当执行testDivide这个Theory测试时,JUnit会把所有的DataPoint数据两两组合,形成一组组的测试数据,并用这些数据分别执行测试。执行上面的测试会输出以下结果:
  Passed with: dividend=0, divisor=2
  Passed with: dividend=0, divisor=8
  Passed with: dividend=2, divisor=2
  Passed with: dividend=2, divisor=8
  Passed with: dividend=8, divisor=2
  Passed with: dividend=8, divisor=8
  (3)如果需要限定某个参数,可以使用@TestOn注解
  import org.junit.experimental.theories.Theories;
  import org.junit.experimental.theories.Theory;
  import org.junit.experimental.theories.suppliers.TestedOn;
  import org.junit.runner.RunWith;
  import static org.junit.Assert.assertEquals;
  @RunWith(Theories.class)
  public class TheoryTest {
  //允许的最大误差 private static final double DELTA = 0.01;
  //如果需要限定某个参数,可以使用@TestOn注解 @Theory
  public void testDivide2(
  @TestedOn(ints = {0, 2, 8}) int dividend,
  @TestedOn(ints = {2, 8}) int divisor
  ) {
  assertEquals(dividend / divisor, Calculator.divide(dividend, divisor), DELTA);
  System.out.println("Passed with: dividend=" + dividend + ", divisor=" + divisor);
  }
  }
  2、自定义实现
  JUnit默认只提供了一个int型的简单 Parameter Supplier 实现,而Theory机制真正的价值在于,能参考@TestedOn的做法,相对简单的完全自定义出可重用 Parameter Supplier,适应于各种复杂要求的限定范围参数值测试场景,满足开发者所需的高度动态自定义范围取值自动化测试,同时保留与一般@Test相同的强大兼容性。
  例:
  (1)定义annotation注解接口Between
  @Retention(RetentionPolicy.RUNTIME)
  // 声明注解接口所使用的委托处理类@ParametersSuppliedBy(BetweenSupplier.class)
  public @interface Between{
  // 声明所有可用参数,效果为 @Between([first = int,] last = int) int first() default 0; // 声明默认值 int last();
  }
  (2)定义委托处理类 BetweenSupplier
  public class BetweenSupplier extends ParameterSupplier {
  @Override
  public List getValueSources(ParameterSignature sig) {
  // 自定义实参值列表 List list = new ArrayList();
  // 获取注解变量 Between between = sig.getAnnotation(Between.class);
  // 获取通过注解@Between传入的first值 int first = between.first();
  // 获取通过注解@Between传入的last值 int last = between.last();
  for (int i = first; i <= last; i++) {
  // PotentialAssignment.forValue(String name, Object value) // name为value的描述标记,没实际作用 // value为实参可选值 list.add(PotentialAssignment.forValue("name", i));
  }
  return list;
  }
  }
  (3)调用方式
  @RunWith(Theories.class)
  public class TheoryDefinedTest {
  @Theory
  public final void test(@Between(last = 0) int i, @Between(first = 3, last= 10) int j) {
  // i 取值为 0(first默认=0,last=0),j 取值为 3-10 System.out.println("i="+i+" j="+j);
  }
  }
  (4)运行结果
  i=0 j=3
  i=0 j=4
  i=0 j=5
  i=0 j=6
  i=0 j=7
  i=0 j=8
  i=0 j=9
  i=0 j=10
  十四、Test fixtures
  Test Fixture是指一个测试运行所需的固定环境,也是就是测试运行之前所需的稳定的、公共的可重复的运行环境,这个“环境”不仅可以是数据,也可以指对被测软件的准备,例如实例化被测方法所依赖的类、加载数据库等等。
  @Before - 在每个@Test方法之前运行
  @After - 在每个@Test方法之后运行
  @BeforeClass - 在所有的@Test方法之前运行一次
  @AfterClass - 在所有的@Test方之后运行一次
  注:
  1、如果创建一个子类继承有fixture注解的父类,那么子类中的@Before方法会在测试方法之前、父类的@Before执行之后执行。
  2、如果@Before方法里抛出了异常,@Test方法会跳过,但是@After还是会执行。
  3、每个测试方法都会在单独的测试类的实例里面运行,@BeforeClass在测试实例创建之前执行。
  public class FixtureTest {
  private static int quantity = 0;
  public FixtureTest() {
  quantity++;
  }
  @BeforeClass
  public static void breforeTestOnlyOnce() throws Exception {
  System.out.println("Run before all test only once..."+ quantity);
  }
  @AfterClass
  public static void afterTestOnlyOnce() throws Exception {
  System.out.println("Run after all test only once..."+ quantity);
  }
  @Before
  public void beforePerTest() {
  System.out.println("Run before per test ..."+ quantity);
  }
  @After
  public void afterPerTest() {
  System.out.println("Run after per test ..."+ quantity);
  }
  //Test Method @Test
  public void testOne() {
  System.out.println("testOne Start..."+ quantity);
  }
  @Test
  public void testTwo() {
  System.out.println("testTwo Start..."+ quantity);
  }
  }
  运行结果:
  Run before all test only once...0
  Run before per test ...1
  testOne Start...1
  Run after per test ...1
  Run before per test ...2
  testTwo Start...2
  Run after per test ...2
  Run after all test only once...2
  十五、Categories 用例分类
  category 和 testSuite的比较:testSuite是类级分组(xx.class),category是用例级分组(@Test),category是testSuite的升级。
  category使用步骤:
  1、创建好测试类,及测试类中的测试用例
  2、创建接口:按用例的分组来创建。
  3、@Category注解:将用例用@Category注解分组。
  4、创建类来执行这些分组的类。
  public interface FastTests { /* category marker */ }
  public interface SlowTests { /* category marker */ }
  public class A {
  @Test
  public void a() {
  fail();
  }
  @Category(SlowTests.class)
  @Test
  public void b() {
  }
  }
  @Category({SlowTests.class, FastTests.class})
  public class B {
  @Test
  public void c() {
  }
  }
  @RunWith(Categories.class)
  @IncludeCategory(SlowTests.class)
  @SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suitepublic class SlowTestSuite {
  // Will run A.b and B.c, but not A.a}
  @RunWith(Categories.class)
  @IncludeCategory(SlowTests.class)
  @ExcludeCategory(FastTests.class)
  @SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suitepublic class SlowTestSuite {
  // Will run A.b, but not A.a or B.c}

      本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
100家互联网大公司java笔试题汇总,填问卷领取~

关注51Testing

联系我们

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

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

沪ICP备05003035号

沪公网安备 31010102002173号