Простой тест JUnit не проходит

Я хочу научиться писать тесты JUnit, и у меня ничего не получается.

Это мой тест:

    @Test
    public void testGetAllCustomers() {
        // given
        List<Customer> customerList = new ArrayList<Customer>();
        customerList.add(c1);
        customerList.add(c2);
        customerList.add(c3);
        given(customerRepository.findAll()).willReturn(customerList);
            
        // when
        List<Customer> resultList = customerService.getAllCustomers();
        
        // then
        assertThat(resultList).hasSize(3);
    }

Проблема в том, что это простое утверждение уже не работает. Возвращаемый список пуст. Я знаю, я новичок во всем этом, но сбой настолько неожиданный с моей точки зрения, что у меня нет подхода, как решить проблему.

Это весь код (не так много):

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;

import java.sql.Timestamp;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class CustomerServiceTests {
    
    @Mock
    private CustomerRepository customerRepository;
    
    @InjectMocks
    private CustomerService customerService;
    
    private Customer c1 = new Customer(
            1L, 
            "Hans Meyer", 
            false, 
            Timestamp.from(Instant.now()),
            null,
            null
    );
    private Customer c2 = new Customer(
            2L, 
            "Marie Hollande", 
            true, 
            Timestamp.from(Instant.now()),
            null,
            null
    );
    private Customer c3 = new Customer(
            3L, 
            "Mohammed Abbas", 
            false, 
            Timestamp.from(Instant.now()),
            null,
            null
    );
    
    @Before
    public void setUp() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    public void testGetAllCustomers() {
        // given
        List<Customer> customerList = new ArrayList<Customer>();
        customerList.add(c1);
        customerList.add(c2);
        customerList.add(c3);
        given(customerRepository.findAll()).willReturn(customerList);
        
        // when
        List<Customer> resultList = customerService.getAllCustomers();
        
        // then
        assertThat(resultList).hasSize(3);
    }
}

Функция для тестирования - это просто, и я знаю, что она работает:

public List<Customer> getAllCustomers() {
        return customerRepository.findAll();
}

На самом деле, я просто хочу научиться писать такие тесты, но уже несколько дней не могу их написать. Примеров и объяснений довольно много, но сколько я ни пытался, у меня пока не получилось работающего теста. Как создать рабочий тест для getAllCustomers()? Спасибо за помощь!

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

Ответы 2

Вы инициализируете свои макеты дважды — сначала с помощью @RunWith(MockitoJUnitRunner.class), а затем с помощью MockitoAnnotations.openMocks(this);

Это означает, что когда вы вводите свой метод setUp:

  • customerRepository указывает на R1
  • customerService.customerRepository указывает на R1

И после этого метода

  • customerRepository указывает на R2
  • customerService.customerRepository указывает на R1

Это означает, что ваш сервис не был повторно инициализирован

Используйте отладчик, чтобы подтвердить это наблюдение.

@InjectMocks javadoc говорит:

MockitoAnnotations.openMocks(this) method has to be called to initialize annotated objects. In above example, openMocks() is called in @Before (JUnit4) method of test's base class. For JUnit3 openMocks() can go to setup() method of a base class. Instead you can also put openMocks() in your JUnit runner (@RunWith) or use the built-in MockitoJUnitRunner.

Большое спасибо! Ваше объяснение действительно помогает мне лучше понять механизмы. Я также всегда стараюсь заглянуть в документы, но, конечно, с таким объемом информации не так просто уследить, если вы новичок во всем этом.

FrozenTree 09.04.2022 00:23
Ответ принят как подходящий

Вот моя рекомендация: вы должны реорганизовать свой код и применить стиль внедрения конструктора, например:

public class CustomerService {

  private final CustomerRepository customerRepository;

  public CustomerService(CustomerRepository customerRepository) {
    this.customerRepository = customerRepository;       // inject customerRepository via constructor
  }

  // ...

}

тогда вам не нужны никакие аннотации Mockito. Просто удалите их.

public class CustomerServiceTests {

    private CustomerRepository customerRepository; 
    private CustomerService customerService;

    // ... init Customer

    @Before
    public void setup() {
      customerRepository = mock(CustomerRepository.class); // inject mocked customerRepository via constructor
      customerService = new CustomerService(customerRepository);
    }

    @Test
    public void testGetAllCustomers() {
        // same as your test code
    }

}

Вы можете видеть, что CustomerServiceTests становится очень простым и тривиальным для тестирования.

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