0


【测试开发篇9】Junit框架


一、认识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);
    }
标签: junit 单元测试 java

本文转载自: https://blog.csdn.net/weixin_56738054/article/details/130139224
版权归原作者 革凡成圣211 所有, 如有侵权,请联系我们删除。

“【测试开发篇9】Junit框架”的评论:

还没有评论