Почему Junit не может выполнить внедрение зависимостей в тесте?

У меня есть примитивный проект Spring-Boot с Junit5 и Lombok. У меня есть простой класс:

public class Calculator {
    public int subtract(int a, int b) {
        return a - b;
    }
}

И создал для него тест:

import lombok.AllArgsConstructor;
import org.junit.jupiter.api.Test;

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

@AllArgsConstructor
class CalculatorTest {
    private final Calculator calculator;

    private static final int SUBTRACTION_RESULT = 2;


    @Test
    void subtractTest() {
        int result = calculator.subtract(5, 3);
        assertEquals(result, SUBTRACTION_RESULT);
    }
}

Сбой теста с:

org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter [final com.udemy.junits.Calculator calculator] in constructor [public com.udemy.junits.CalculatorTest(com.udemy.junits.Calculator)].

Насколько я понимаю, он не может инициализировать и создать экземпляр калькулятора. Я попытался сделать это без Ломбока и добавил конструктор:

public CalculatorTest(Calculator calculator) {
    this.calculator = calculator;
}

Был такой же результат. Затем я создал это таким образом, используя @BeforeAll:

@BeforeAll
    static void init() {
        calculator = new Calculator();
    }

Это сработало. Внедрение зависимостей здесь недоступно, потому что у нас нет контекста приложения? Или я неправильно понимаю? Можно ли здесь выполнить внедрение зависимостей без создания экземпляра калькулятора var as new Calculator() ?

В вашем тесте нет ничего, связанного со Spring, так как же Spring узнает, что вы хотите внедрить зависимости в свой тест? Если вам нужен полноценный интеграционный тест, добавьте @SpringBootTest, иначе добавьте @ExtendWith(SpringExtension.class) и предоставьте @ContextConfiguration... Все это вы также можете найти в отличной документации Spring и Spring Boot.

M. Deinum 31.10.2022 15:29

Что ты пытаешься сделать? Инициализация объекта калькулятора новым экземпляром Calculator работает нормально.

hfontanez 31.10.2022 15:50
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
2
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваш последний блок кода правильный и является стандартной практикой, вам не нужен конструктор в этом тестовом классе для экземпляра Calculator.

Для тестового класса вы должны определить поля и инициализировать их методом @BeforeAll или @BeforeEach.

Использование конструктора для тестового класса в JUnit зарезервировано для параметризованных модульных тестов, поэтому вы получаете сообщение об ошибке, указывающее, что вам не хватает ParameterResolver. Это будет пример, когда вы будете использовать конструктор для параметризованного теста:

public class Calculator {
    public int subtract(int a, int b) {
        return a - b;
    }
}

@RequiredArgsConstructor
@RunWith(Parameterized.class)
class CalculatorTest {
    private final int x;
    private final int y;
    private final int z;
    private Calculator calculator;
 
    // Constructor is generated by lombok with @RequiredArgsConstructor
    // and accepts three parameters, x, y, and z

    @BeforeEach
    void setUp() {
        calculator = new Calculator();
    }

    @Test
    void testSubtract() {
        assertEquals(z, calculator.subtract(x, y));
    }
    
    /**
     * This method will pass each parameter into the constructor
     * of this test class. In this case, the testSubtract method
     * will be ran 4 times with each set of parameters.
     */
    @Parameterized.Parameters
    static Collection parameters() {
        return Arrays.asList(
            new Object[][] {
               {5, 3, 2},
               {10, 1, 9},
               {120, 40, 80},
               {1, 1, 0}
            }
        );
    }
}

Вы можете найти дополнительные сведения о параметризованном модульном тестировании здесь для JUnit 4 и здесь для JUnit 5.

Другие вопросы по теме