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();

我会按照罗伯特所说的去做,并尝试消除静电,这样它的行为可能更符合您的预期。