简单的 JUnit 测试失败

Simple JUnit test fails

我想学习如何编写 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() 创建工作测试?感谢您的帮助!

你初始化你的模拟两次 - 首先是 @RunWith(MockitoJUnitRunner.class) 然后是 MockitoAnnotations.openMocks(this);

这意味着当您进入设置方法时:

  • customerRepository 指向 R1
  • customerService.customerRepository指向R1

在这个方法之后

  • customerRepository 指向 R2
  • customerService.customerRepository指向R1

这意味着您的服务不是 re-initialized

使用调试器来确认这个观察结果。

@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.

这是我的建议:您应该重构代码并应用 constructor-injection 样式,如下所示:

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 变得非常简单且易于测试。