目录
一、认识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);
    }


















