自由的羽毛 发表于 2025-3-20 12:02:27

maven项目进行单位测试具体教程


[*]
[*]
[*]为什么使用mock


举个例子:
类 A 必要调用类 B 和类 C,而类 B 和类 C 又必要调用其他类如 D、E、F 等,假设类 D 是一个外部服务,那就会很难测,因为你的返回效果会直接的 受外部服务影响,导致你的单位测试大概今天会过、但来日诰日就过不了了。
而当我们引入 Mock 测试时,就可以创建一个假的对象,替换掉真实的 Bean B 和 C,这样在调用B、C的方法时,实际上就会去调用这个假的 Mock 对象的方法,而我们就可以自己设定这个 Mock 对象的参数和盼望效果,让我们可以专注在测试当前的类 A,而不会受到其他的外部服务影响,这样测试效率就能提高很多。
     比如你现在想要测试一个方法是否是正常的,但是这个方法中有很多调用数据库的代码,那么我们就可以在每个调用数据库的地方打桩,模仿一下访问完数据库之后的返回值,这样我们就可以在测试的时候避免访问数据库了,可以非常高效地完成我们的单位测试,已到达验证我们写的方法到底对不对的目标。
mockB=mock(B.class);
   mockC=mock(C.class);

[*]
[*]
[*]新建maven项目


File->new->project->maven->Project SDK 已经精确设置,通常为jdk版本-》如果必要,可以勾选 Create from archetype,并选择一个 Maven 原型(archetype),比如 maven-archetype-quickstart 用于快速创建一个简单的 Maven 项目


[*]GroupId: 输入项目标构造或公司名称(如 com.example )。
[*]ArtifactId: 输入项目标名称(如 my-maven-project)。
[*]Version: 输入项目标版本号(默认为 1.0-SNAPSHOT)。
[*]Project name: 输入项目在 IDEA 中的表现名称。
[*]Project location: 选择项目保存的路径。
直接finlish,IDEA 会自动下载 Maven 依赖并构建项目。你可以在底部的 Maven 工具窗口中查看进度。
创建完成后,项目结构如下:


[*]src/main/java: 存放 Java 源代码。
[*]src/test/java: 存放测试代码。
[*]pom.xml: Maven 项目标核心设置文件。   
[*]
[*] 运行项目




[*]在 src/main/java 中创建一个简单的 Java 类,并编写 main 方法。
[*]右键点击类文件,选择 Run 来运行程序。   
[*]
[*] 管理依赖




[*]如果必要添加依赖,可以在 pom.xml 文件的 <dependencies> 标签中添加依赖项,IDEA 会自动下载并管理这些依赖。   
[*]
[*] 找不到类junit


删除C:\Users\<你的用户名>\.m2\repository\org\junit\junit 文件夹,maven-->clean一下
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5CADMINI~1%5CAppData%5CLocal%5CTemp%5Cksohtml5116%5Cwps1.jpg&pos_id=52r0oEGL

[*]
[*]
[*] 单位测试a+b简单案例


目次结构:
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5CADMINI~1%5CAppData%5CLocal%5CTemp%5Cksohtml5116%5Cwps2.jpg&pos_id=TH4s5MkS
App.java类
package org.example;
public class App {
    public static int add(int a, int b) {
        return a + b;
    }
}

AppTest.java类
package org.example;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class AppTest {
    @Test
    void testAdd() {
        assertEquals(5, App.add(2,  3));
    }
}
设置文件pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>dycs</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <!-- JUnit 5 API -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.10.0</version>
            <scope>test</scope>
        </dependency>
        <!-- JUnit 5 引擎 -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.10.0</version>
            <scope>test</scope>
        </dependency>
        <!-- JUnit 平台引擎 -->
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-engine</artifactId>
            <version>1.10.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
运行AppTest.java,效果
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2F%2FC%3A%5CUsers%5CADMINI~1%5CAppData%5CLocal%5CTemp%5Cksohtml5116%5Cwps3.jpg&pos_id=8XS5yEQ2

[*]
[*]
[*] 生成测试用例的快捷键


CTRL+shift+t

[*]
[*]
[*] mock使用when控制行为(方法)返回值


@Test
void testSaleByAgeForChildren() {//儿童半折
    when(mockPassenger.getAge()).thenReturn(10);
    ticket.saleByAge(mockPassenger.getAge());//调用方法
    assertEquals(50,ticket.getPrice());
}
测试类
package fit5171.monash.edu;
public class Ticket
{
    private int ticket_id;
    private int price;
    Flight flight;
    private boolean classVip; //indicates if this is bussiness class ticket or not
    private boolean status; //indicates status of ticket: if it is bought by someone or not
    Passenger passenger;

    public Ticket(int ticket_id,int price, Flight flight, boolean classVip, Passenger passenger)
    {
        this.ticket_id=ticket_id;
        this.price = price;
        this.flight = flight;
        this.classVip = classVip;
        this.status = false;
        this.passenger=passenger;
    }

    public Ticket() {

    }

    public int getTicket_id() {
        return ticket_id;
    }

    public void setTicket_id(int ticket_id) {
        this.ticket_id = ticket_id;
    }

    public int getPrice() { return price; }

    public void setPrice(int price)
    {
        this.price = price;
        saleByAge(passenger.getAge()); //changes price of the ticket according to the age category of passenger
        serviceTax( ); //changes price by adding service tax to the ticket
    }

    public void saleByAge(int age)
    {
        int price = getPrice();
        if(age < 15)
        {
            price-=(int)price*0.5;//50% sale for children under 15
            this.price=price;

        } else if(age>=60){
            this.price=0; //100% sale for elder people
        }
    }

    public Flight getFlight() {
        return flight;
    }

    public void setFlight(Flight flight) {
        this.flight = flight;
    }

    public boolean getClassVip() {
        return classVip;
    }

    public void setClassVip(boolean classVip) {
        this.classVip = classVip;
    }

    public boolean ticketStatus()
    {
        return status;
    }

    public void setTicketStatus(boolean status)
    {
        this.status = status;
    }

    public void serviceTax(){
        this.price *= 1.12;
    } //12% service tax

    public Passenger getPassenger() {
        return passenger;
    }

    public void setPassenger(Passenger passenger) {
        this.passenger = passenger;
    }

    public String toString()
    {
        return"Ticket{" +'\n'+
                "Price=" + getPrice() + "KZT, " + '\n' +
                getFlight() +'\n'+ "Vip status=" + getClassVip() + '\n' +
                getPassenger()+'\n'+ "Ticket was purchased=" + ticketStatus() + "\n}";
    }
}

测试代码
package fit5171.monash.edu;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;

class TicketTest {
    private Ticket ticket;
    private Passenger mockPassenger;

    @BeforeEach
    void setUp() {
        // 初始化 Mock 对象
        mockPassenger = mock(Passenger.class);
        ticket = new Ticket(1, 100, null, false, mockPassenger); // 初始化 Ticket 对象
    }

    @Test
    void testSaleByAgeForChildren() {
        // 模仿乘客年龄为 10 岁
        when(mockPassenger.getAge()).thenReturn(10);

        // 调用方法
        ticket.saleByAge(mockPassenger.getAge());

        // 验证代价是否精确应用 50% 折扣
        assertEquals(50, ticket.getPrice(),  "Price should be 50 for children under 15.");
    }

    @Test
    void testSaleByAgeForElderly() {
        // 模仿乘客年龄为 65 岁
        when(mockPassenger.getAge()).thenReturn(65);

        // 调用方法
        ticket.saleByAge(mockPassenger.getAge());

        // 验证代价是否精确设置为 0
        assertEquals(0, ticket.getPrice(),  "Price should be 0 for elderly people aged 60 or above.");
    }

    @Test
    void testSaleByAgeForAdults() {
        // 模仿乘客年龄为 30 岁
        when(mockPassenger.getAge()).thenReturn(30);

        // 调用方法
        ticket.saleByAge(mockPassenger.getAge());

        // 验证代价是否保持不变
        assertEquals(100, ticket.getPrice(),  "Price should remain 100 for adults aged 15 to 59.");
    }

    @Test
    void testSaleByAgeWithZeroPrice() {
        // 模仿乘客年龄为 10 岁,并将初始代价设置为 0
        ticket.setPrice(0);
        when(mockPassenger.getAge()).thenReturn(10);

        // 调用方法
        ticket.saleByAge(mockPassenger.getAge());

        // 验证代价是否保持为 0
        assertEquals(0, ticket.getPrice(),  "Price should remain 0 if original price is 0.");
    }
    
}

[*]
[*]
[*] mock对象是不能实现具体的业务逻辑



package fit5171.monash.edu;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;

class SaleByAgeTest {
    private Ticket ticket;
    private Flight flight;
    private Passenger passenger;

    @BeforeEach
    void setUp() {
//        ticket=new Ticket(1,100, flight, false, passenger);
//        ticket=mock(Ticket.class);
    }
    @Test
    void testSaleByAgeForChildren() {
//        when(ticket.getPrice()).thenReturn(100);
//        System.out.print(ticket.getPrice());
       ticket.saleByAge(10);//这样子不会调用saleByage函数,因为这是mock对象,是空实现
       verify(ticket).saleByAge(10);//验证saleByAge方法是否被调用,若未被调用,则报错
//        doNothing().when(ticket).saleByAge(10); // 设置 saleByAge 方法的行为
//        // 调用方法
//        ticket.saleByAge(10);
//        // 验证其他逻辑(如果有)
//        assertEquals(50, ticket.getPrice());//事实上,不大概走saleByAge的业务逻辑,因为是mock对象
//--------------------------------------------------------------------------------
        Ticket ticket = spy(new Ticket());
        ticket.setPrice(100);
        // 调用方法
        ticket.saleByAge(10);  // 调用实际逻辑
        // 验证逻辑
        assertEquals(50, ticket.getPrice());  // 验证代价是否精确
    }

}

[*]
[*]
[*]  怎么使用mock实现业务逻辑,从而实现某个类的具体方法的单位测试


目标:A类依赖其他类,则把其他类给mock,然后A类必要真实对象。这样就可以测试A类中的方法。

举例:Ticket类必要调用Flight类和Passenger类,必要测试Ticket类中的saleByAge()方法。我们只需mock 一下Flight类和Passenger类 ,实例化对象 Ticket类,并按照Ticket类的构造方法Ticket()传参。这样我们即使没有Flight类和Passenger类的代码,也可以测试Ticket类的方法。                                                   .
被测试类
package fit5171.monash.edu;
public class Ticket
{
    private int ticket_id;
    private int price;
    Flight flight;
    private boolean classVip; //indicates if this is bussiness class ticket or not
    private boolean status; //indicates status of ticket: if it is bought by someone or not
    Passenger passenger;

    public Ticket(int ticket_id,int price, Flight flight, boolean classVip, Passenger passenger)
    {
        this.ticket_id=ticket_id;
        this.price = price;
        this.flight = flight;
        this.classVip = classVip;
        this.status = false;
        this.passenger=passenger;
    }

    public Ticket() {

    }

    public int getTicket_id() {
        return ticket_id;
    }

    public void setTicket_id(int ticket_id) {
        this.ticket_id = ticket_id;
    }

    public int getPrice() { return price; }

    public void setPrice(int price)
    {
        this.price = price;
        saleByAge(passenger.getAge()); //changes price of the ticket according to the age category of passenger
        serviceTax( ); //changes price by adding service tax to the ticket
    }

    public void saleByAge(int age)
    {
        int price = getPrice();
        if(age < 15)
        {
            price-=(int)price*0.5;//50% sale for children under 15
            this.price=price;

        } else if(age>=60){
            this.price=0; //100% sale for elder people
        }
    }

    public Flight getFlight() {
        return flight;
    }

    public void setFlight(Flight flight) {
        this.flight = flight;
    }

    public boolean getClassVip() {
        return classVip;
    }

    public void setClassVip(boolean classVip) {
        this.classVip = classVip;
    }

    public boolean ticketStatus()
    {
        return status;
    }

    public void setTicketStatus(boolean status)
    {
        this.status = status;
    }

    public void serviceTax(){
        this.price *= 1.12;
    } //12% service tax

    public Passenger getPassenger() {
        return passenger;
    }

    public void setPassenger(Passenger passenger) {
        this.passenger = passenger;
    }

    public String toString()
    {
        return"Ticket{" +'\n'+
                "Price=" + getPrice() + "KZT, " + '\n' +
                getFlight() +'\n'+ "Vip status=" + getClassVip() + '\n' +
                getPassenger()+'\n'+ "Ticket was purchased=" + ticketStatus() + "\n}";
    }
}
测试代码
package fit5171.monash.edu;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;

class SaleByAgeTest {
    private Ticket ticket;
    private Flight mockFlight;
    private Passenger mockPassenger;

    @BeforeEach
    void setUp() {
        mockFlight=mock(Flight.class);
        mockPassenger=mock(Passenger.class);
        ticket=new Ticket(1,100, mockFlight, false, mockPassenger);
    }
    @Test
    void testSaleByAgeForChildren() {//儿童半折
        ticket.saleByAge(10);//调用方法
//        System.out.print(ticket.getPrice());//获取代价
        assertEquals(50,ticket.getPrice());
    }
    @Test
    void testSaleByAgeForelder() {//老年人免费
        ticket.saleByAge(70);//调用方法
//        System.out.print(ticket.getPrice());//获取代价
        assertEquals(0,ticket.getPrice());
    }
}


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: maven项目进行单位测试具体教程