简单的 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 变得非常简单且易于测试。
我想学习如何编写 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 变得非常简单且易于测试。