目录
一、认识Junit框架
Junit和Selenium的关系是什么
导入Junit框架+common-io包
二、Junit框架的使用
2.1Junit有哪些常用注解
2.1.1@Test注解
2.1.2BeforeEach
2.1.3@BeforeAll
2.1.4@AfterAll
2.1.5@AfterEach
2.2Junit的断言
Assertions.assertEquals(期待值,真实值);
2.2.1Assertions.assertNotEquals("百度一下",text)
2.2.2Assertions.assertTrue(text.equals("百度一下"))
2.2.3Assertions.assertNull(a);
三、用例的执行顺序
①针对方法的排序
为什么需要用到juit的排序功能
四、测试套件(Suit)
@Suite
@SelectClasses({待测试的类.class})
@SelectPackages("包名")
五、参数化
5.1@ParameterizedTest、@ValueSource(strings = {})
5.2@CsvSource(value={"第一组数据","第二组数据"})
如果参数当中包含逗号:",",就需要使用单引号转义字符串
5.3读取文件参数:@CsvFileSource(resources="/文件名称")
5.3.1读取其他磁盘文件的操作:指定文件为files=...
5.4动态参数(单参数版本)
5.5动态参数(多参数版本)
六、对于重要测试场景的截图
第一步:定位到需要的页面
第二步:调用getSrceenshotAs方法,传入的擦参数是OutputTpye.FILE;
第三步:新建一个File类,指定路径;
第四步:调用copyFile方法,把生成的文件放到指定的目录当中
一、认识Junit框架
Junit是一个开源的Java语言的单元测试框架。
回顾一下,单元测试就是在编码阶段,一般情况下,由开发进行的测试。
Junit和Selenium的关系是什么
Junit是单元测试框架,而selenium是web自动化测试框架。如果把selenium比作灯泡,那么junit就是电灯。因此:一般情况下,junit负责运行selenium脚本编写的代码。
导入Junit框架+common-io包
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.8.1</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite</artifactId>
<version>1.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
二、Junit框架的使用
2.1Junit有哪些常用注解
2.1.1@Test注解
这一个注解作用于方法上面,表示这个方法是一个测试用例。当@Test注解作用在一个方法上面的时候,表示这一个方法是可以直接运行的,无需通过main方法来调用。
2.1.2BeforeEach
在执行每一个被@Test修饰的方法之前,都会执行一次@BeforeEach注释的方法。
@BeforeEach
void aaa(){
System.out.println("pre");
}
@Test
void bbb(){
System.out.println("bbb");
}
@Test
void ccc(){
System.out.println("ccc");
}
每执行一个@Test之前,就需要执行一次@BeforeEach注释的方法
运行类上面的运行按钮:
2.1.3@BeforeAll
首先,被@BeforeAll注释的方法一定是静态的。
其次,不同于@BeforeEach的是,@BeforeAll注释的方法一定是静态的,并且只会在加载外部类的时候执行一次,并不会在每一个方法执行之前再次执行了。
public class Test1 {
@BeforeAll
static void aaa(){
System.out.println("pre");
}
@Test
void bbb(){
System.out.println("bbb");
}
@Test
void ccc(){
System.out.println("ccc");
}
}
2.1.4@AfterAll
被这个注解修饰的方法也必须是静态的,在每一个@Test之后进行修饰。
public class Test1 {
@BeforeAll
static void aaa(){
System.out.println("pre");
}
@Test
void bbb(){
System.out.println("bbb");
}
@Test
void ccc(){
System.out.println("ccc");
}
@AfterAll
static void afterAll(){
System.out.println("end...");
}
}
运行结果:
2.1.5@AfterEach
同理,在每一个@Test注释的方法执行结束的末尾,都会执行一次@AfterEach注释的方法。
public class Test1 {
@BeforeEach
void aaa(){
System.out.println("pre");
}
@Test
void bbb(){
System.out.println("bbb");
}
@Test
void ccc(){
System.out.println("ccc");
}
@AfterEach
void afterAll(){
System.out.println("end...");
}
}
运行结果:
2.2Junit的断言
写自动化测试,结果要么是成功的,要么是失败的,不存在成功一半的情况。
那么就需要使用到断言:assert,断言预期结果和真实结果是否一致。
Assertions.assertEquals(期待值,真实值);
当期待值和真实值一致的时候,这个断言才不会抛出异常;
当期待值和真实值不一致的时候,就会抛出异常;
代码实现:
public class Test2 {
FirefoxDriver driver;
@BeforeEach
public void get(){
driver=new FirefoxDriver();
//捕捉到这一个页面
driver.get("https://www.baidu.com");
}
@Test
public void testOne(){
//尝试获取"百度一下"的文本框
String text=driver.findElement(By.cssSelector("#su")).getAttribute("value");
//使用AssertEquals来进行断言
Assertions.assertEquals("百度一下",text);
}
@AfterEach
public void after(){
driver.quit();
}
}
如果运行的结果一致,那么就提示测试用例通过:
2.2.1Assertions.assertNotEquals("百度一下",text)
与Assertions.assertEquals(期待值,真实值)相反。
只有不一致的时候,测试用例才会通过。
2.2.2Assertions.assertTrue(text.equals("百度一下"))
传入的参数应该是一个返回值为boolean类型的表达式;
@Test
public void assertTrueTest(){
String text=driver.findElement(By.cssSelector("#su")).getAttribute("value");
//如果返回true,那么测试用例通过,否则测试用例不通过
Assertions.assertTrue(text.equals("百度一下"));
}
同理,还有AssertFalse
2.2.3Assertions.assertNull(a);
@Test
public void assertNull(){
String a=null;
Assertions.assertNull(a);
}
如果一个引用为null,那么默认测试用例通过。
同理,还有Assertions.assertNotNull(),那么一个引用不为null的时候,测试用例才通过。
三、用例的执行顺序
①针对方法的排序
第一步:在这个类上面添加注解:@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
第二步:
使用@Order(执行顺序)作用在方法上面,表示是第几个执行;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class Test2 {
FirefoxDriver driver;
@BeforeEach
@Order(1)
public void get(){
driver=new FirefoxDriver();
//捕捉到这一个页面
driver.get("https://www.baidu.com");
}
@Test
@Order(2)
public void testOne(){
//尝试获取"百度一下"的文本框
String text=driver.findElement(By.cssSelector("#su")).getAttribute("value");
Assertions.assertNotEquals("百度一下",text);
}
@Test
@Order(3)
public void assertTrueTest(){
String text=driver.findElement(By.cssSelector("#su")).getAttribute("value");
//如果返回true,那么测试用例通过,否则测试用例不通过
Assertions.assertTrue(text.equals("百度一下"));
}
@AfterEach
public void after(){
driver.quit();
}
}
为什么需要用到juit的排序功能
如果用例之间存在关联关系(存在耦合)(但是不是绝对有关联关系),那么就需要手动指定用例的执行顺序。因为各个测试用例的执行顺序是无序的。
这样就可以避免出现各个测试用例之间执行顺序不正确的情况。
四、测试套件(Suit)
测试套件,用于把所有的测试用例都执行起来。
@Suite
这一个注解作用于类上面,用于执行所有的测试用例。
@SelectClasses({待测试的类.class})
这个注解和上面的注解需要配合使用,这样才可以一起执行待测试类的测试用例。
当然也可以传递多个.class对象。
@Suite
@SelectClasses({Test1.class,Test2.class})
public class SuitTest {
}
运行结果:
@SelectPackages("包名")
扫描这一个包下面包含了@Test注解的方法的类。
@Suite
@SelectPackages("TestFile")
public class SuitTest {
}
但是扫描的包不可以和当前的类在同一个包下面;
需要注意的是,这种情况下面,被扫描的类一定是xxxTest这样命名的,否则是扫描不到的。
五、参数化
对于一个测试用例,可能会测试传入的参数是多种的情况;
例如对于一个文本框进行测试,可以测试多种输入的情况:
如下图:如果为每一个输入的name都定义一个方法,那么就显得非常冗余,于是就引入了参数化。
5.1@ParameterizedTest、@ValueSource(strings = {})
第一个注解@Parameterized作用在方法上面,用来表示这个方法支持传入多个参数;
第二个注解@ValueSource用于指定传入参数的类型;例如:strings={}就表示传入的是一个string类型的数组;
ints={2,3,4,5}表示传入的参数是一个int类型的数组;
但是,同一个@ValueSource注解当中只支持一种数据类型。
运行结果:
5.2@CsvSource(value={"第一组数据","第二组数据"})
其中,每一组数据当中对应方法传入的参数的值。采用","来分割。
@ParameterizedTest
@CsvSource(value = {"小明,20","小红,30","小李,40"})
public void printStringAndInteger(String name,int age){
System.out.println("name:"+name+";age="+age);
}
当然,一组数据当中的分隔符也不一定采用系统默认的","分割,也可以采用自定义的分隔符。
@ParameterizedTest
@CsvSource(value = {"小明-20","小红-20","小李-40"},delimiter = '-')
public void printStringAndAge(String name,int age){
System.out.println("name:"+name+";age="+age);
}
用户自定义的分隔符:
如果参数当中包含逗号:",",就需要使用单引号转义字符串
5.3读取文件参数:@CsvFileSource(resources="/文件名称")
第一步:在resources目录下面新建一个文件,并且指定名称;
第二步:在文件当中以逗号的方式分割每一组参数;
然后运行程序:
5.3.1读取其他磁盘文件的操作:指定文件为files=...
@ParameterizedTest
@CsvFileSource(files = "E:\\OJSystem\\src\\main\\resources\\my.csv")
public void printStringAndAge3(String name,int age){
System.out.println("name:"+name+";age="+age);
}
5.4动态参数(单参数版本)
第一步:定义提供数据的方法,必须声明为静态;返回值为一个Stream对象;方法内部调用Stream.of(参数列表);
第二步:定义dyNatickTest(String x)方法获取参数;并用@MethodSource()指定
第三步:输出参数。
@ParameterizedTest
@MethodSource("methodDemo")
void dyNatickTest(String x){
System.out.println(x);
}
static Stream<String> methodDemo(){
return Stream.of("张三","李四","王五");
}
如果@MethodSource当中不指定参数的名称,那么就会调用跟测试用例同名的静态方法
5.5动态参数(多参数版本)
第一步:新建一个测试方法,并且指定多个参数。使用@ParameterizedTest和@MethodSource注解同时作用
第二步:新建一个和测试用例同名的静态方法;
第三步:在静态方法当中调用Stream.of()方法,并且传入的参数为多个Arguments.arguments(第一步创建方法的参数列表)
代码实现:
@ParameterizedTest
@MethodSource
void paramsTest(String name,int age){
System.out.println("name:"+name+";age :"+age);
}
/**
* 多参数的版本
* Stream对象@return
*/
static Stream<Arguments> paramsTest(){
return Stream.of(Arguments.arguments("lucy",29),Arguments.arguments("lili",30)
,Arguments.arguments("lisi",40));
}
六、对于重要测试场景的截图
第一步:定位到需要的页面
第二步:调用getSrceenshotAs方法,传入的擦参数是OutputTpye.FILE;
第三步:新建一个File类,指定路径;
第四步:调用copyFile方法,把生成的文件放到指定的目录当中
@Test
public void screenShortTest() throws IOException, InterruptedException {
//百度搜索关键字
driver.findElement(By.cssSelector("#kw")).sendKeys("selenium");
driver.findElement(By.cssSelector("#su")).click();
//屏幕截图,把截图的文件存放到指定的位置
//以文件的形式存储
File srcFile=driver.getScreenshotAs(OutputType.FILE);
//把截图的文件存放到指定的目录下面
File destFile=new File("E:/OJSystem/src/test/Files/img.png");
Thread.sleep(1000);
FileUtils.copyFile(srcFile,destFile);
}