【问题标题】:Junit Tests pass individually but fail when run togetherJunit 测试单独通过但一起运行时失败
【发布时间】:2023-03-08 16:29:02
【问题描述】:

我目前正在为学校做作业,但我正在努力应对考试部分。由于某种原因,单元测试在单独运行时运行良好,但在一起运行时运行良好。我知道这与我在他们之间共享对象有关,因为我不应该基于我之前的搜索,但我无法终生弄清楚需要改变什么来解决这个问题。 AppointmentService 类和 AppointmentServiceTest 类的代码如下。任何帮助将不胜感激,因为我已经坚持了一段时间,并且知道这可能是其他人会立即看到的东西。

AppointmentServiceTest 类


import static org.junit.jupiter.api.Assertions.*;

import java.text.ParseException;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import main.Appointment;
import main.AppointmentService;

class AppointmentServiceTest {

    private static AppointmentService appointmentService;
    
    @BeforeAll
    static void setUp() {
        appointmentService = AppointmentService.getService();
    }
    
    @Test
    void testAddAppointmentSuccess() throws ParseException {
        Appointment appointment = new Appointment("123456", "2022-10-01", "Appointment Description String");
        assertTrue(appointmentService.addAppointment(appointment));
        
        Appointment cachedAppointment = appointmentService.getAppointment(appointment.getAppointmentId());
        
        assertTrue(cachedAppointment != null);
        assertTrue(cachedAppointment.getAppointmentId().equals("123456"));
        assertTrue(cachedAppointment.getAppointmentDate().equals("2022-10-01"));
        assertTrue(cachedAppointment.getAppointmentDescription().equals("Appointment Description String")); 
    }
    
    @Test
    void testAddMultipleAppointmentsSuccess() throws ParseException {
        Appointment appointment1 = new Appointment("123456", "2022-10-01", "Appointment Description String");
        Appointment appointment2 = new Appointment("1234567", "2022-10-02", "Appointment Description String2");
        
        assertTrue(appointmentService.addAppointment(appointment1));
        Appointment cachedAppointment1 = appointmentService.getAppointment(appointment1.getAppointmentId());
        
        assertTrue(cachedAppointment1 != null);
        assertTrue(cachedAppointment1.getAppointmentId().equals("123456"));
        assertTrue(cachedAppointment1.getAppointmentDate().equals("2022-10-01"));
        assertTrue(cachedAppointment1.getAppointmentDescription().equals("Appointment Description String"));    
        
        assertTrue(appointmentService.addAppointment(appointment2));
        Appointment cachedAppointment2 = appointmentService.getAppointment(appointment1.getAppointmentId());
        
        assertTrue(cachedAppointment2 != null);
        assertTrue(cachedAppointment2.getAppointmentId().equals("1234567"));
        assertTrue(cachedAppointment2.getAppointmentDate().equals("2022-10-02"));
        assertTrue(cachedAppointment2.getAppointmentDescription().equals("Appointment Description String2"));
        
    }
    
    @Test
    void testAddAppoitnmentDuplicateIdFail() throws ParseException {
        Appointment appointment1 = new Appointment("123456", "2022-10-01", "Appointment Description String");
        Appointment appointment2 = new Appointment("123456", "2022-10-01", "Appointment Description String");


        assertTrue(appointmentService.addAppointment(appointment1));
        assertFalse(appointmentService.addAppointment(appointment2));
    }
    
    @Test
    void testGetAppointmentAndUpdateSuccess() throws ParseException {
        Appointment appointment = new Appointment("123456", "2022-10-01", "Appointment Description String");
        assertTrue(appointmentService.addAppointment(appointment));
        
        Appointment updatedAppointment = appointmentService.getAppointment(appointment.getAppointmentId());
        updatedAppointment.setAppointmentDate("2022-10-02");
        updatedAppointment.setAppointmentDescription("New Description");
        
        updatedAppointment = appointmentService.getAppointment(updatedAppointment.getAppointmentId());
        
        assertTrue(updatedAppointment.getAppointmentDescription().equals("New Description"));
        assertTrue(updatedAppointment.getAppointmentDate().equals("2022-10-02"));
    }
    
    @Test
    void testGetAppointmentAndDeleteSuccess() throws ParseException {
        Appointment appointment = new Appointment("123456", "2022-10-01", "Appointment Description String");
        
        assertTrue(appointmentService.addAppointment(appointment));
        
        appointment = appointmentService.getAppointment(appointment.getAppointmentId());
        assertTrue(appointment != null);
        
        assertTrue(appointmentService.deleteAppointment(appointment.getAppointmentId()));
        assertTrue(appointmentService.getAppointment(appointment.getAppointmentId()) == null);
    }
    
    @Test
    void testDeleteInvalidAppointmentFail() {
        String invalidAppointmentIdString = "123";
        
        assertFalse(appointmentService.deleteAppointment(invalidAppointmentIdString));
    }

还有 AppointmentService 类


import java.util.HashMap;
import java.util.Map;

public class AppointmentService {

    private static AppointmentService reference = new AppointmentService();
    private final Map<String, Appointment> appointmentList;
    
    AppointmentService() {
        this.appointmentList = new HashMap<String, Appointment>();
    }
    
    public static AppointmentService getService() {
        return reference;
    }
    
    public boolean addAppointment(Appointment appointment) {
        boolean isSuccess = false;
        
        if(!appointmentList.containsKey(appointment.getAppointmentId())) {
            appointmentList.put(appointment.getAppointmentId(), appointment);
            isSuccess = true;
        }
        return isSuccess;
    }
    
    public boolean deleteAppointment(String appointmentId) {
        return appointmentList.remove(appointmentId) != null;
    }
    
    public Appointment getAppointment(String appointmentId) {
        return appointmentList.get(appointmentId);
    }
    
}


 

【问题讨论】:

    标签: java junit


    【解决方案1】:

    您正在为您的 2 测试使用相同的 appointmentService 实例,并在您的 2 测试中添加具有相同 ID(“123456”)的约会。因此,当测试一起运行时,您的下一个测试将始终失败,因为您假设 ID“123456”在第二个测试中不存在,但确实存在。

    您应该为每个测试创建一个新的appointmentService,因为单元测试 = 单独测试,尤其是当您的测试实例有一些状态时。

    【讨论】:

    • 一种方法是在创建AppointmentService的设置方法上使用@BeforeEach注释。
    • 所以我认为是这种情况并将@BeforeAll 切换为@BeforeEach,此时测试根本没有运行。我是否遗漏了一些东西才能正常工作?
    • 在您的@BeforeAll appointmentService = new AppointmentService() 中执行此操作。同时删除reference 字段和getService 方法。它们没用,也是一种不好的做法。
    • 我删除了引用和 getService 方法,并且能够成功运行我的测试。我使用了单例,因为它是以前的作业解决类似问题的方式,不幸的是,我以同样的方式解决了这个问题。感谢大家的帮助!
    【解决方案2】:

    去掉这里的静态

    private static AppointmentService appointmentService;\
    

    还有设置方法。还将@BeforeAll 更改为@BeforeEach 它将为每个测试创建新的约会服务以隔离测试用例。

    此外,如果没有任何理由将引用作为静态,那么类本身最好重构(摆脱静态引用)自制单例是一种反模式。 现在,当代码调用 getReference 时,它​​总是返回相同的实例,这就是它在运行所有测试时不起作用的原因。

    另见https://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html 希望对你有帮助

    【讨论】:

    • 我尝试了你的建议,但我仍然遇到同样的问题,单独运行时所有测试都通过,但一起运行时出现 4 次失败。
    • 原因是私有的 STATIC AppointmentService reference = new AppointmentService();通话中的静态(非测试)。由于它是 statijc,因此您对套件中的每个测试都有相同的参考。它是静态的有什么特别的原因吗?我猜你想要一个单例,它看起来不像通常的单例。如果没有任何理由要自制单例(顺便说一句,这是反模式),则只需重构代码本身(摆脱静态字段引用)
    • 非常感谢您的所有反馈和建议。我使用静态并创建单例的原因是因为我的教授就是这样编写最后一个作业的解决方案的,这非常相似,所以我认为我会以同样的方式解决这个问题。我进行了您建议的更改,并且当一起独立运行时,我能够成功处理所有测试。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多