I want to learn how to write JUnit tests and I fail completely.
This is my test:
@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);
}
The problem is that this simple assertion already fails. The returned list is empty. I know, I am new to all of this, but the failure is so unexpected from my point of view that I have no approach on how to solve the problem.
This is the whole code (not that much):
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);
}
}
The function to test is just this and I know that it works:
public List<Customer> getAllCustomers() {
return customerRepository.findAll();
}
Actually, I just want to learn how to write such tests, but for days I have been failing to write one. There are quite a few examples and explanations, but no matter what I try, I have not yet managed a working test. How to create a working test for getAllCustomers()? Thank you for your help!
CodePudding user response:
You initialize your mocks twice - first by @RunWith(MockitoJUnitRunner.class)
and then with MockitoAnnotations.openMocks(this);
This means that when you enter your setUp method:
- customerRepository points to R1
- customerService.customerRepository points to R1
And after this method
- customerRepository points to R2
- customerService.customerRepository points to R1
Which means that your service was not re-initialized
Use a debugger to confirm this observation.
@InjectMocks javadoc says:
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.
CodePudding user response:
Here's my recommendation: you should refactor your code and apply constructor-injection style, like this:
public class CustomerService {
private final CustomerRepository customerRepository;
public CustomerService(CustomerRepository customerRepository) {
this.customerRepository = customerRepository; // inject customerRepository via constructor
}
// ...
}
then, you don't need any Mockito annotations. Just remove them.
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
}
}
You can see that CustomerServiceTests becomes very simple and trivial to test.