一、背景
现在有A类,B类,C类,A类依赖B类,依赖C类,如果想要测试A类中的某个方法的业务逻辑。A类依赖其他类,则把其他类给mock,然后A类需要真实对象。这样就可以测试A类中的方法。
举例:Ticket类需要调用Flight类和Passenger类,需要测试Ticket类中的saleByAge()方法。我们只需mock 一下Flight类和Passenger类 ,实例化对象 Ticket类,并按照Ticket类的构造方法Ticket()传参。这样我们即使没有Flight类和Passenger类的代码,也可以测试Ticket类的方法。
二、被测试类Ticket.java的代码
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}";
}
}
三、测试Ticket类中的SaleByAge方法代码
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() {//儿童半折
when(mockPassenger.getAge()).thenReturn(10);
ticket.saleByAge(mockPassenger.getAge());//调用方法
assertEquals(50,ticket.getPrice());
}
@Test
void testSaleByAgeForelder() {//老年人免费
when(mockPassenger.getAge()).thenReturn(70);
ticket.saleByAge(mockPassenger.getAge());//调用方法
assertEquals(0,ticket.getPrice());
}
}
四、运行结果如下
五、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>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.8.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>5.2.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
六、注意事项
mock是模拟对象,是空实现。如果要实现具体的业务逻辑的单元测试,必须创建真实对象,真实对象中涉及到类,可以mock。
使用when指定行为的值,如指定mock乘客的年龄为10.
@Test
void testSaleByAgeForChildren() {//儿童半折
when(mockPassenger.getAge()).thenReturn(10);
ticket.saleByAge(mockPassenger.getAge());//调用方法
assertEquals(50,ticket.getPrice());
}