Junit:为每个测试设置新的对象实例,当 运行 一次进行多个测试时会发生一些奇怪的事情
Junit: Setting up new instance of object for every test, something strange happens when run multiple tests at once
我一直在尝试编写 JUnit 测试来测试程序,但似乎出了点问题,我无法弄清楚是什么。该程序按预期工作,但当 运行 在一起时,单元测试表现异常。
我想为每个测试创建一个 ParkingLotManager 对象的新实例,并尝试在每个测试方法以及 @BeforeEach 中实例化一个新对象。尽管如此,当 运行 一个接一个地进行测试时,一切正常,但是当 运行 在一起时,一切都会变得糟糕。
以前我无法将 @BeforeEach 方法获取到 运行,但这似乎是一个 Maven 兼容性问题。它现在似乎至少可以打印出来。
我一整天都在为此苦苦挣扎,重写了一百万次,如果有点乱,请见谅。
谁能告诉我我做错了什么?
也欢迎对代码的其他反馈。
待测ParkingLotManagerclass:
package com.mycompany.graduatecase;
import java.util.*;
import com.mycompany.graduatecase.ParkingSpot;
import static com.mycompany.graduatecase.SpaceShipParking.calculateDuration;
import static com.mycompany.graduatecase.SpaceShipParking.calculatePrice;
import static com.mycompany.graduatecase.SpaceShipParking.input;
import java.time.LocalDateTime;
public class ParkingLotManager {
private static ArrayList<ParkingSpot> parkingLot = new ArrayList<ParkingSpot>();
private static ParkingRecords parkingRecords = new ParkingRecords();
public ParkingLotManager(int levels, int parkingsPerLevel) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 15; j++) {
parkingLot.add(new ParkingSpot(i+1, j+1));
}
}
}
public void displayLot(){
for (int i = 0; i < parkingLot.size();i++)
{
System.out.println("Våning: " + parkingLot.get(i).level + " Number: " + parkingLot.get(i).number + " Is available: " + parkingLot.get(i).isAvailable);
}
}
public ParkingSpot getParkingSpot(int level, int number){
for (int i = 0; i < parkingLot.size();i++)
if (parkingLot.get(i).level == level)
if(parkingLot.get(i).number == number){
return parkingLot.get(i);
}
return null;
}
public ParkingSpot getAvailableParkingSpot(){
for (int i = 0; i < parkingLot.size();i++){
if (parkingLot.get(i).isAvailable){
return parkingLot.get(i);
}
}
return null;
}
/*
* Registers a designated parking spot on first available parking spot,
* starting on level 1, spot 1.
*/
public void registerParking(String regNo){
if (getAvailableParkingSpot() == null){
System.out.println("No available parkings right now, please come back later. ");
}else{
ParkingSpot parkingSpot = getAvailableParkingSpot();
System.out.println("\nPlease park on assigned parkingspot.");
System.out.println("Level: " + parkingSpot.level + " Number: " + parkingSpot.number);
parkingSpot.spotTaken();
parkingRecords.addRecord(regNo, parkingSpot);
}
}
/*
* Returns -1 when no found parking for regNo, otherwise returns duration for parking.
*/
public int registerPickup(String regNo){
ParkRecord parkingRecord = parkingRecords.findLatestParkingOnRegNo(regNo);
int durationParked = 0;
if ( parkingRecord == null){
System.out.println("Vi hittade inte din parkering. Försök igen.");
}else{
parkingRecord.setTo(LocalDateTime.now());
ParkingSpot spot = parkingRecord.getParkingSpot();
getParkingSpot(spot.level, spot.number).spotFreed();
durationParked = calculateDuration(parkingRecord.getFrom(), parkingRecord.getTo());
return durationParked;
}
return -1;
}
}
这是测试 class:
package com.mycompany.graduatecase;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import static org.assertj.core.api.Assertions.*;
public class ParkingLotManagerTest {
private ParkingLotManager parkingLot;
public ParkingLotManagerTest() {
}
@BeforeAll
public static void setUpClass() {
}
@AfterAll
public static void tearDownClass() {
}
@BeforeEach
public void setUp() {
parkingLot = new ParkingLotManager(3, 15);
}
@AfterEach
public void tearDown() {
}
/**
* Test of getParkingSpot method, of class ParkingLotManager.
*/
@Test
public void testGetParkingSpot() {
System.out.println("getParkingSpot");
int level = 1;
int number = 1;
ParkingSpot expectedObject = new ParkingSpot(level, number);
ParkingSpot actualObject = parkingLot.getParkingSpot(level, number);
// assertThat(actualObject)
// .usingRecursiveComparison()
// .isEqualTo(expectedObject);
assertEquals(expectedObject.level, actualObject.level);
assertEquals(expectedObject.number, actualObject.number);
}
@Test
public void testGetAvailableParkingSpot() {
System.out.println("getAvailableParkingSpot returns right object");
int level = 1;
int number = 1;
//ParkingLotManager parkingLot = new ParkingLotManager(3, 15);
ParkingSpot expectedObject = new ParkingSpot(level, number);
ParkingSpot actualObject = parkingLot.getAvailableParkingSpot();
assertThat(actualObject)
.usingRecursiveComparison()
.isEqualTo(expectedObject);
}
@Test
public void testGetAvailableParkingSpot2() {
System.out.println("getAvailableParkingSpot returns right object after registering 3 parkings");
int level = 1;
int number = 4;
//ParkingLotManager parkingLot = new ParkingLotManager(3, 15);
ParkingSpot expectedObject = new ParkingSpot(level, number);
parkingLot.registerParking("123");
parkingLot.registerParking("234");
parkingLot.registerParking("456");
ParkingSpot actualObject = parkingLot.getAvailableParkingSpot();
assertThat(actualObject)
.usingRecursiveComparison()
.isEqualTo(expectedObject);
}
@Test
public void testGetAvailableParkingSpot3() {
System.out.println("getAvailableParkingSpot returns right object after registering 3 parkings and removing 1");
int level = 1;
int number = 2;
//ParkingLotManager parkingLot = new ParkingLotManager(3, 15);
ParkingSpot expectedObject = new ParkingSpot(level, number);
parkingLot.registerParking("123");
parkingLot.registerParking("234");
parkingLot.registerParking("456");
parkingLot.registerPickup("234");
ParkingSpot actualObject = parkingLot.getAvailableParkingSpot();
assertThat(actualObject)
.usingRecursiveComparison()
.isEqualTo(expectedObject);
}
}
删除:
private ParkingLotManager parkingLot;
...
@BeforeEach
public void setUp() {
parkingLot = new ParkingLotManager(3, 15);
}
并添加局部变量
ParkingLotManager parkingLot = new ParkingLotManager(3, 15);
在每个测试或等效的构造函数(例如getParkingLotManager3_15()
)开始时不重复代码。
你不应该 属性 属于测试 class,当你 运行 测试并行
我同意罗伯特的快速猜测。我觉得他一针见血
如果您的测试 运行ning 并发,它们将具有不同的 ParkingLotManager 对象,这些对象都共享相同的基础数据,这显然会成为一个大的并发问题。即使它们 运行 连续,上次测试的数据仍将保留,因此未来的测试将不会从“空”开始。
因此,如果您按顺序知道测试 运行(而不是同时进行),则可以通过在 @AfterEach 中添加对新函数 parkingLot.reset() 的调用来测试该理论;
在 ParkingLotManager 中实施 .reset() 函数,其中 .reset() 清除底层(静态)列表。这样,每次前一个测试完成时,下一个测试都有一个“新”列表可供使用。这将使它“看起来”好像您正在获得一个干净的 ParkingLotManager,而不是一个带有旧列表句柄的新对象。
private static ArrayList<ParkingSpot> parkingLot = new ArrayList<ParkingSpot>();
private static ParkingRecords parkingRecords = new ParkingRecords();
我会按照罗伯特所说的去做,并尝试消除静电,这样它的行为可能更符合您的预期。
我一直在尝试编写 JUnit 测试来测试程序,但似乎出了点问题,我无法弄清楚是什么。该程序按预期工作,但当 运行 在一起时,单元测试表现异常。
我想为每个测试创建一个 ParkingLotManager 对象的新实例,并尝试在每个测试方法以及 @BeforeEach 中实例化一个新对象。尽管如此,当 运行 一个接一个地进行测试时,一切正常,但是当 运行 在一起时,一切都会变得糟糕。
以前我无法将 @BeforeEach 方法获取到 运行,但这似乎是一个 Maven 兼容性问题。它现在似乎至少可以打印出来。
我一整天都在为此苦苦挣扎,重写了一百万次,如果有点乱,请见谅。
谁能告诉我我做错了什么?
也欢迎对代码的其他反馈。
待测ParkingLotManagerclass:
package com.mycompany.graduatecase;
import java.util.*;
import com.mycompany.graduatecase.ParkingSpot;
import static com.mycompany.graduatecase.SpaceShipParking.calculateDuration;
import static com.mycompany.graduatecase.SpaceShipParking.calculatePrice;
import static com.mycompany.graduatecase.SpaceShipParking.input;
import java.time.LocalDateTime;
public class ParkingLotManager {
private static ArrayList<ParkingSpot> parkingLot = new ArrayList<ParkingSpot>();
private static ParkingRecords parkingRecords = new ParkingRecords();
public ParkingLotManager(int levels, int parkingsPerLevel) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 15; j++) {
parkingLot.add(new ParkingSpot(i+1, j+1));
}
}
}
public void displayLot(){
for (int i = 0; i < parkingLot.size();i++)
{
System.out.println("Våning: " + parkingLot.get(i).level + " Number: " + parkingLot.get(i).number + " Is available: " + parkingLot.get(i).isAvailable);
}
}
public ParkingSpot getParkingSpot(int level, int number){
for (int i = 0; i < parkingLot.size();i++)
if (parkingLot.get(i).level == level)
if(parkingLot.get(i).number == number){
return parkingLot.get(i);
}
return null;
}
public ParkingSpot getAvailableParkingSpot(){
for (int i = 0; i < parkingLot.size();i++){
if (parkingLot.get(i).isAvailable){
return parkingLot.get(i);
}
}
return null;
}
/*
* Registers a designated parking spot on first available parking spot,
* starting on level 1, spot 1.
*/
public void registerParking(String regNo){
if (getAvailableParkingSpot() == null){
System.out.println("No available parkings right now, please come back later. ");
}else{
ParkingSpot parkingSpot = getAvailableParkingSpot();
System.out.println("\nPlease park on assigned parkingspot.");
System.out.println("Level: " + parkingSpot.level + " Number: " + parkingSpot.number);
parkingSpot.spotTaken();
parkingRecords.addRecord(regNo, parkingSpot);
}
}
/*
* Returns -1 when no found parking for regNo, otherwise returns duration for parking.
*/
public int registerPickup(String regNo){
ParkRecord parkingRecord = parkingRecords.findLatestParkingOnRegNo(regNo);
int durationParked = 0;
if ( parkingRecord == null){
System.out.println("Vi hittade inte din parkering. Försök igen.");
}else{
parkingRecord.setTo(LocalDateTime.now());
ParkingSpot spot = parkingRecord.getParkingSpot();
getParkingSpot(spot.level, spot.number).spotFreed();
durationParked = calculateDuration(parkingRecord.getFrom(), parkingRecord.getTo());
return durationParked;
}
return -1;
}
}
这是测试 class:
package com.mycompany.graduatecase;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import static org.assertj.core.api.Assertions.*;
public class ParkingLotManagerTest {
private ParkingLotManager parkingLot;
public ParkingLotManagerTest() {
}
@BeforeAll
public static void setUpClass() {
}
@AfterAll
public static void tearDownClass() {
}
@BeforeEach
public void setUp() {
parkingLot = new ParkingLotManager(3, 15);
}
@AfterEach
public void tearDown() {
}
/**
* Test of getParkingSpot method, of class ParkingLotManager.
*/
@Test
public void testGetParkingSpot() {
System.out.println("getParkingSpot");
int level = 1;
int number = 1;
ParkingSpot expectedObject = new ParkingSpot(level, number);
ParkingSpot actualObject = parkingLot.getParkingSpot(level, number);
// assertThat(actualObject)
// .usingRecursiveComparison()
// .isEqualTo(expectedObject);
assertEquals(expectedObject.level, actualObject.level);
assertEquals(expectedObject.number, actualObject.number);
}
@Test
public void testGetAvailableParkingSpot() {
System.out.println("getAvailableParkingSpot returns right object");
int level = 1;
int number = 1;
//ParkingLotManager parkingLot = new ParkingLotManager(3, 15);
ParkingSpot expectedObject = new ParkingSpot(level, number);
ParkingSpot actualObject = parkingLot.getAvailableParkingSpot();
assertThat(actualObject)
.usingRecursiveComparison()
.isEqualTo(expectedObject);
}
@Test
public void testGetAvailableParkingSpot2() {
System.out.println("getAvailableParkingSpot returns right object after registering 3 parkings");
int level = 1;
int number = 4;
//ParkingLotManager parkingLot = new ParkingLotManager(3, 15);
ParkingSpot expectedObject = new ParkingSpot(level, number);
parkingLot.registerParking("123");
parkingLot.registerParking("234");
parkingLot.registerParking("456");
ParkingSpot actualObject = parkingLot.getAvailableParkingSpot();
assertThat(actualObject)
.usingRecursiveComparison()
.isEqualTo(expectedObject);
}
@Test
public void testGetAvailableParkingSpot3() {
System.out.println("getAvailableParkingSpot returns right object after registering 3 parkings and removing 1");
int level = 1;
int number = 2;
//ParkingLotManager parkingLot = new ParkingLotManager(3, 15);
ParkingSpot expectedObject = new ParkingSpot(level, number);
parkingLot.registerParking("123");
parkingLot.registerParking("234");
parkingLot.registerParking("456");
parkingLot.registerPickup("234");
ParkingSpot actualObject = parkingLot.getAvailableParkingSpot();
assertThat(actualObject)
.usingRecursiveComparison()
.isEqualTo(expectedObject);
}
}
删除:
private ParkingLotManager parkingLot;
...
@BeforeEach
public void setUp() {
parkingLot = new ParkingLotManager(3, 15);
}
并添加局部变量
ParkingLotManager parkingLot = new ParkingLotManager(3, 15);
在每个测试或等效的构造函数(例如getParkingLotManager3_15()
)开始时不重复代码。
你不应该 属性 属于测试 class,当你 运行 测试并行
我同意罗伯特的快速猜测。我觉得他一针见血
如果您的测试 运行ning 并发,它们将具有不同的 ParkingLotManager 对象,这些对象都共享相同的基础数据,这显然会成为一个大的并发问题。即使它们 运行 连续,上次测试的数据仍将保留,因此未来的测试将不会从“空”开始。
因此,如果您按顺序知道测试 运行(而不是同时进行),则可以通过在 @AfterEach 中添加对新函数 parkingLot.reset() 的调用来测试该理论;
在 ParkingLotManager 中实施 .reset() 函数,其中 .reset() 清除底层(静态)列表。这样,每次前一个测试完成时,下一个测试都有一个“新”列表可供使用。这将使它“看起来”好像您正在获得一个干净的 ParkingLotManager,而不是一个带有旧列表句柄的新对象。
private static ArrayList<ParkingSpot> parkingLot = new ArrayList<ParkingSpot>();
private static ParkingRecords parkingRecords = new ParkingRecords();
我会按照罗伯特所说的去做,并尝试消除静电,这样它的行为可能更符合您的预期。