测试用例

在PnxTest设计中,一个测试用例等同于一个测试方法(@Test注解); 一个测试方法由一个或多个测试步骤(测试步骤使用@Step注解)组成。

用例属性

Annotation 注解 Scope作用域 Description 描述
@Test Method 表明是一个测试方法。
-只有标注为@Test的方法才会被PnxTest执行
-私有方法(private)不支持
@DisplayName Method 定义测试用例标题。纯文本格式,最大长度80个字符
@Descrption Method 定义测试用例的详细描述。支持html标签
@Level Method 定义测试用例的级别:L1, L2,L3...
@Issue Method 表明该测试用例所关联的问题ID,如@Issue("bug-321", "bug-543")
@Order Method 测试方法的执行默认是按字母升序执行的,通过该注解手动设定用例的执行顺序。order小的用例先执行
@Disabled Method或Class Skip测试用例,值为disabled原因。例如:@Disabled("Bug没有修复,当前分支不支持该功能")
@RepeatedCount Method 定义测试方法重复执行的次数。重复次数大于1才有效
@DataDriven Method 数据驱动。从外部文件读取数据来执行。默认支持csv, txt格式的文件
@Controller Class 测试控制类,module:用例模块;maintainer: 用例的开发维护者
@BeforeAll Method 一个类中所有测试方法开始执行前,运行该方法
@AfterAll Method 一个类中所有测试方法执行完成后,运行该方法
@BeforeEach Method 每一个测试方法执行前,运行该方法
@AfterEach Method 每一个测试方法执行后,运行该方法

@DisplayName

  • 一个测试方法如果没有@DisplayName注解, 展示的用例标题为方法名(test user should not be able to login without password)。例如:
@Test
void testUserShouldNotBeAbleToLoginWithoutPassword(){
    //...    
}  
  • 测试方法如果有@DisplayName注解, 展示的用例标题为@DisplayName的值(无密码应该无法登录系统)。例如:
@Test
@DisplayName("无密码应该无法登录系统")
void testUserCanNotLoginWithoutPassword(){
  //...
}
  • 测试方法如果使用了@Issue注解,用例标题将自动添加issue id(无密码应该无法登录系统(#bug-123, #task-456)). 例如:
@Test
@DisplayName("无密码应该无法登录系统")
@Issue("bug-123", "task-456")
void testUserCanNotLoginWithoutPassword(){
  //...
}

@Disabled

使用该注解skip单个测试方法或者一个类中的所有测试方法。例如:

//disable单个方法
@Test
@DisplayName("无密码应该无法登录系统")
@Disabled("#Bug123没有被修复")
void testUserCanNotLoginWithoutPassword(){
  //...
}

//disable全部方法
@Controller(module="userService")
@Disabled("#Task-456没有开发完成")
public class UserServiceTest{
  @Test
  @DisplayName("合法账号应该能成功登录系统")
  void testUserCanLoginSuccessfullyWithValidAccount(){
  //...
    }

  @Test
  @DisplayName("无密码应该无法登录系统")
  void testUserCanNotLoginWithoutPassword(){
  //...
    }

}

@Level

使用该注解定义一个测试用例的级别。PnxTest定义了L1-L4 四个级别。例如:

@Controller(module="userService")
public class UserServiceTest{
  @Test
  @DisplayName("合法账号应该能成功登录系统")
  @Level(Levels.L1)
  void testUserCanLoginSuccessfullyWithValidAccount(){
  //...
    }

  @Test
  @DisplayName("无密码应该无法登录系统")
  @Level(Levels.L2)
  void testUserCanNotLoginWithoutPassword(){
  //...
    }

}

各个Level代表的含义可以根据自身业务或流程规范去定义,这里摘一份通用的供参考:

级别 含义 描述 参考占比 划分依据
L1 基本 核心基本功能,1级用例的数量应受到控制 10% 阻断性的,核心功能错误,导致用户工作流程中断;系统内部错误导致服务不可用、系统宕机、数据遭到破坏、丢失等
L2 重要 2级测试用例是实际系统的重要功能,2级用例数量较多 20% 一些功能交互相关, 各种应用场景、使用频率较高的正常功能测试用例。实际使用频率比较高的用例,重要功能未实现或者错误,导致用户重要工作场景不能满足,不可上线
L3 一般 3级测试用例的涉及系统的一般功能,3级用例数量较多 60% 使用频率低于2级的用例。如特殊字符、请求超时、可靠性测试等。实际使用频率不高、对系统业务功能影响不大的模块或功能的测试用例,一般性功能未实现或者错误,不影响用户工作流程或重要工作
L4 生僻 该级别的用例一般比较少,主要是一些异常功能 10% 该用例对应较生僻的预置条件和数据设置。涉及显示/提示信息/边界值等小范围功能,未按照UI设计提示、提示不友好(非产品、用户)语言、无提示等。(占比10%)

@Order

一个类中测试方法的执行默认是按字母升序进行的,如果需要特定的执行顺序(例如一些用例需要在某个用例后面执行),可以使用该注解设定, @Order(n): n小的先执行:

@Test
@DisplayName("合法账号应该能成功登录系统")
@Level(Levels.L1)
@Order(1)
void testUserCanLoginSuccessfullyWithValidAccount(){
  //...
}

@Test
@DisplayName("无密码应该无法登录系统")
@Level(Levels.L3)
@Order(2)
void testUserCanNotLoginWithoutPassword(){
  //...
}

@RepeatedCount

对于一些需要重复执行的场景,使用该注解指定重复执行的次数。@RepeatedCount(n): n代表运行的次数,n>1该注解才有效

@Test
@DisplayName("重复运行50次,100%成功")
@RepeatedCount(50)
void run50TimesAndCheckSuccessCount(){
  //...
}

@Test
@DisplayName("重复运行50次,96%以上成功")
@RepeatedCount(value = 50, successPercentage = 96)
void run50TimesAndCheckSuccessCount(){
  //...
}

特别说明:一个测试用例多次重复执行后,PnxTest会在测试报告中展示详细统计信息:最大耗时、最小耗时、平均耗时以及每一次执行记录等

@DataDriven

某些场景我们可能需要从文件中读取数据 作为输入数据源 来驱动执行测试用例。当前PnxTest支持CSV和txt文件的数据源。示例如下:

//csv文件作为数据源,有header
@Test
@DataDriven(value = "testdata2.csv", withHeader = true)
@DisplayName("数据驱动csv文件:使用map传参")
public void testDataDrivenUsingCsvFile(Map<String, String> data){
  if(data.get("name").equals("David")){
    PnxAssert.assertThat(data.get("sex")).isEqualTo("male");
    PnxAssert.assertThat(data.get("city")).isEqualTo("shanghai");
  }
}

//txt文件作为数据源,有header
@Test
@DataDriven(value = "testdata.txt", withHeader = true)
@DisplayName("数据驱动.txt文件:使用map传递参数")
public void testDataDrivenUsingTextFile(Map<String, Object> data){
  if(data.get("name").equals("Ming")){
    PnxAssert.assertThat(data.get("mobile")).isEqualTo("18222223333");
    PnxAssert.assertThat(data.get("city")).isEqualTo("shanghai");
  }
}

//txt文件作为数据源,有header
@Test
@DataDriven(value = "testdata.txt", withHeader = true)
@DisplayName("数据驱动.txt文件:依次传递多个参数")
public void testDataDrivenUsingTextFile(String name, long mobile, String city){
  if(name.equals("Ming")){
    PnxAssert.assertThat(mobile).isEqualTo(18222223333L);
  }
}

特别说明:

1)数据驱动数据源文件 需放置在项目指定的test-config目录下
2)数据源文件中无论有多少条数据执行,都会被PnxTest当作“一条测试用例”
3) 测试报告中会详细记录每一条数据的执行结果

生命周期

TestClass
├── @BeforeAll           //测试类实例化后运行
│   └── @BeforeEach      //每个测试方法调用前运行
│   └── TestMethod1      //测试方法1
│   └── @AfterEach       //每个测试方法执行完成后运行
│  
│   └── @BeforeEach      //每个测试方法调用前运行
│   └── TestMethod2      //测试方法2
│   └── @AfterEach       //每个测试方法执行完成后运行
│ 
│   └── @BeforeEach      //每个测试方法调用前运行
│   └── TestMethod3      //测试方法3
│   └── @AfterEach       //每个测试方法执行完成后运行
├── @AfterAll            //测试类中所有的测试方法执行结束后运行