1)Junit是一个开源的JAVA语言的单元测试框架,也是JAVA方向使用最广泛的单元测试框架,使用JAVA开发者都应该学习junit框架,并且掌握单元测试的编写
2)selenium和Junit都可以被导入到maven项目里面
3)先进行创建maven项目,导入相关依赖
4)selenium4==java8==junit5
5)官网:JUnit 5
org.seleniumhq.selenium selenium-java 4.0.0 org.junit.jupiter junit-jupiter 5.8.2 test org.junit.platform junit-platform-reporting 1.8.2 org.junit.platform junit-platform-suite 1.8.2 test
一)Junit的注解:
1)@Test表示一个方法或者是一个用例
1.1)加上这个注解之后,就不需要再创建main函数进行创建在程序执行的入口了就可以让程序执行起来;
1.2)况且还可以单独的运行假设当前测试方法在其他的测试方法之后,那么我们通过main方法来顺序执行测试用例的时候,如果某一个方法挂了,那么后面的方法都没有办法再去执行了,就会造成测试用例的浪费
2)@BeforeEach,@BeforeAll
表示被@BeforeEach注解修饰的方法应该在其他任何方法执行之前都要执行一遍,无论是所有方法一起执行,还是每一个方法单独执行;
表示被@BeforeAll注解修饰的方法应该在其他方法所有一个方法执行之前只需要执行一遍就可以了,使用@BeforeAll注解修饰的方法必须是静态方法
1)下面是我们点击全部运行之后,@BeforeAll修饰的方法只是执行一次
2)但是当每一个Test方法运行之前也是都需要执行一次@BeforeAll修饰的方法
3)@BeforeAll和@Test联合修饰起来的方法不能单独运行
如果当前所有方法都进行运行,那么当所有方法运行完成之前@BeforeAll只会执行一次
如果单个的运行每一个方法,那么在每一个方法执行完成之后都会执行一次@BeforeAll方法
3)@AfterEach和@AfterAll注解
1)@AfterAll方法:
1.1)被@AfterAll修饰的方法必须也是静态方法
1.2)被@AfterAll和@Test来联合修饰的方法不能单独运行
1.3)被@AfterAll修饰的方法
1.4)如果当前所有方法都进行运行,那么当所有方法运行完成之后@After只会执行一次
1.4)如果单个的运行每一个方法那么在每一个方法执行完成之后都会执行一次@AfterAll方法
2)@AfterEach方法
表示被@AfterEach注解修饰的方法应该在其他任何方法执行之后都要执行一遍,无论是所有方法一起执行,还是每一个方法单独执行;
3)@Disabled :表示测试类或测试方法不执行
4)@Timeout :表示测试方法运行如果超过了指定时间将会返回错误,里面的参数默认是秒
5)@DisplayName :为测试类或者测试方法设置展示名称,就是一个标识
6)@ParameterizedTest :表示方法是参数化测试,搭配与@ValueSource或者@CsvSource注解来进行使用
6.1)String类型参数
public class TestBaiDu { @ParameterizedTest @ValueSource(strings={"abc","def"}) public void run(String s){ System.out.println(s); } }
6.2)针对int类型的参数来说
二)断言
写自动化测试,结果要么是成功的,要么是失败的,我们就需要使用断言来进行判断自动化测试的结果是否符合我们的预期
1)AssertEqual(expect,actual),进行校验实际的值和预期的值是否匹配相等;
ChromeDriver driver=new ChromeDriver(); //1.测试百度首页展示元素是否正确 @Test void Test_BaiDu1(){ //1.先进行跳转到百度界面 driver.get("http://www.baidu.com"); //2.检测百度输入框中的按钮展示文字是否合理 String message=driver.findElement(By.cssSelector("#su")).getAttribute("value"); Assertions.assertEquals(message,"百度一下"); //如果测试不通过,就会打印预期结果和实际结果之间的区别 }
2)AssertNotEqual(expect,actual),进行校验实际的值和预期的值是否不相等不匹配;
3)AssertTrue(里面传递的是Boolean类型表达式)
4)AssertFalse(参数)
这里面的参数的值要么是True要么是False,参数就是Boolean类型
ChromeDriver driver=new ChromeDriver(); //1.测试百度首页展示元素是否正确 @Test void Test_BaiDu1(){ //1.先进行跳转到百度界面 driver.get("http://www.baidu.com"); //2.检测百度输入框中的标题是否正确 String message=driver.getTitle(); Assertions.assertTrue(message.equals("百度一下,你就知道")); //如果测试不通过,就会打印预期结果和实际结果之间的区别 }
5)AssertNull()
6)AssertNotNull()
@Test void Test(){ String str1=null; String str2="abc"; Assertions.assertNull(str1); Assertions.assertNotNull(str2); }
三)用例的执行顺序
一)为什么要用junit里面的排序方法呢?
1)junit的默认执行顺序是不确定的,官方文档并没有给出一个明确的执行顺序
2)假设说如果用例之间存在着关联关系,没有进行解耦合,前一个方法中的用例就会关联影响到后一个用例的执行,就需要手动的指定的执行顺序
二)测试用例之间都存在着这样的一个关联关系吗?
1)在编写测试用例的时候要保证用例之间的一个独立性,尽量解耦合,比如说上一个用例执行的一个结果,从页面上获取了一个元素;
2)那么这个元素可能会作为下一个方法中用例的参数的输入,耦合性很低,也就是说我们要使用这个参数来继续执行下一个方法;
3)尽量保持用例之间的独立性
但是我们仍然可以使用junit里面提供的方法来进行手动的设置用例的执行顺序
1)@TestMethodOrder(MethodOrderer.OrderAnnotation.class)用来修饰类,标识当前类使用方法来进行排序
2)每一个方法加上的@order注解表示明确标注各个方法的执行顺序
最后可以从程序的执行结果来进行观察
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class TestBaiDu { @Test @Order(1) public void start(){ System.out.println("aaa"); } @Test @Order(3) public void run(){ System.out.println("bbb"); } @Test @Order(2) public void sum(){ System.out.println("ccc"); } @Test @Order(4) public void sub(){ System.out.println("ddd"); } }
四)测试套件
测试套件就是将我们所有的指定的用例都来进行一起执行
1)选择指定类添加到套件里面来执行
加上@Suite和@SelectClasses({类名.class,类名.class})
1.1)测试类名称必须以Test或Tests结尾,例如UserMgmtTests,DeviceMgmtTest等
1.2)我们的用例必须要加上@Test注解
//这是一个测试套件,将我们所有的用例都来执行起来 @Suite @SelectClasses({AutoTest1.class, AutoTest2.class}) public class TestSuite { }
2)选择指定的包添加到套件中执行
1)在这里仍然使用的是@Suite注解和@SelectClasses注解将包添加到测试套件里面,执行包下面的所以以Test命名的文件中的所有@Test注解的用例;
2)测试用例之间是保持着一个完备的独立性的,一个测试用例失败了不会影响到其他的测试用例的执行;
五)参数化
1)通过用例来构造参数@ParamterizedTest注解标注方法类型为多参数,只是告诉方法需要用到多参数这是不需要再次添加@Test,如果添加了@Test的测试用例是要多执行一遍的;
2)强调参数的来源
2.1)@ValueSource(类型={参数1,参数2,参数3}),适用于单个类型的参数的方法
这里面的类型包括int,String,float
如果想要进行查找相关API的用法,就去查ValueSource (JUnit 5.9.2 API)
2.1.1)使用String类型的参数
public class TestSuite { @ParameterizedTest @ValueSource(strings={"张三","李四","王二麻子"}) public void start(String s){ System.out.println(s); } }
2.1.2)使用int类型的参数
public class TestSuite { @ParameterizedTest @ValueSource(ints={1,2,3}) public void start(int age){ System.out.println(age); } }
2.2)适用于多个类型的参数的方法
1)@CsvSource(value={"振鹏,20","zhangsan,30","lisi,60"})
2)@CsvSource(value={"参数1,参数2,....",.....)
public class TestSuite { @ParameterizedTest @CsvSource(value={"zhangsan,20","lisi,30","huangtao,89"}) public void start(String name,int age){ System.out.println(name); System.out.println(age); } }
3)参数之间的分隔符默认是",",但是我们可以通过delimiterString来指定参数之间的分隔符
@ParameterizedTest @CsvSource(value={"李佳伟&12503487","张三&778896","王二麻子&101010"},delimiterString = "&") public void start(String username,String password){ System.out.println(username); System.out.println(password); }
4)如果参数中包含逗号,那么使用单引号来作为转义字符
3)使用文件的方式,包括项目目录中的resources目录和本地磁盘上任意的文件
5)如果参数真的是非常的多,在代码中编写不算特别好看,就可以借助文件注入的方式来进行添加,@CsvFileSource(source="source下面的文件"),source就是我们的文件路径;
@ParameterizedTest @CsvFileSource(resources = "/My.csv") public void run(String username,String password){ System.out.println(username); System.out.println(password); }
6)指定我们的本地磁盘的文件
@CsvFileSource(files="绝对路径")
里面的绝对路径是指定为本地任意文件下面的csv文件
数字类型的参数必须有值,否则会导致用例执行失败
@ParameterizedTest @CsvFileSource(files = "D:\\TestData.csv") public void GetSource(String username,String password){ System.out.println(username); System.out.println(password); }
4)动态参数
4.1)使用@MethodSource(""),参数是数据来源的方法名字,单参数类型
4.2)正常情况下,参数是数据来源的方法名字,如果不指定数据来源,那么则找和用例同名的静态方法
4.3)数据来源的方法一定要是静态类型的方法
@ParameterizedTest//声明当前的方法是多参数的 @MethodSource("GetDataSource")//指定数据来源是来自于哪一个方法 public void runDemo(String username){ System.out.println(username); } public static Stream
GetDataSource(){ return Stream.of("张三","李四","王二麻子"); } @ParameterizedTest @MethodSource public void runDemo(String username){ System.out.println(username); } public static Stream
runDemo(){ return Stream.of("张三","李四","王二麻子"); } 4.4)支持多参数的方法
@ParameterizedTest @MethodSource public void runData(String username,String password){ System.out.println(username); System.out.println(password); } static Stream
runData(){ return Stream.of(Arguments.arguments("张三","12503487"),Arguments.arguments("李四","123456678"),Arguments.arguments("王二麻子","778896")); }