hi every one i have some problem
i have a test class called TestUserService
#RunWith(MockitoJUnitRunner.class)
public class TestUserService {
#InjectMocks
UserService userService;
#Mock
InMemory inMemory;
#Before
public void init(){
MockitoAnnotations.initMocks(this);
}
#Test
public void registry(){
System.out.println("hi");
UserDto userDto=new UserDto(1L,"abed","alrhman",26);
UserDto userDto1=new UserDto(1L,"abdallah","almasre",27);
UserDto userDto2=new UserDto(1L,"bisher","alahmad",35);
UserDto userDto3=new UserDto(1L,"ibrahem","alrabe",32);
userService.registry(userDto);
userService.registry(userDto1);
userService.registry(userDto2);
userService.registry(userDto3);
System.out.println("\"registry\" = " + "registry");
verify(inMemory,times(0)).save(userDto.ToDTO(userDto));
verify(inMemory,times(1)).save(userDto1.ToDTO(userDto1));
verify(inMemory,times(0)).save(userDto2.ToDTO(userDto2));
verify(inMemory,times(0)).save(userDto3.ToDTO(userDto3));
}
}
when run the test i want save new user by UserService class and UserService will go to InMemory class
#Service
public class UserService implements IUserService {
private final InMemory inMemory;
public UserService(InMemory inMemory){
this.inMemory=inMemory;
}
#Override
public UserDto registry(UserDto userDto) {
User user=userDto.ToDTO(userDto);
User user1=inMemory.save(user);
return user.toEntity(user1);
}
}
the problem in InMemory Class it is a local repository has Map Called users and some other methods
after called registry(User user) method
the Map has it when debugger 'this' is not available
and the user param not receive into the save(User user) method and the debugger dont walk of any point check
private Map<Long,User> users=new HashMap<>();
#Override
public User save(User user) {
user.setId(1L);
users.put(1L,user);
return user;
}
and this is Image when debugger code
if you attention save(User user) dont has object or any value and users map not avalible
In your test, you are defining InMemory as a mock. A mock is an object that emulates the behavior of a real object according to how you configure such mock to behave. Having said that, your InMemory object in your test is not a real InMemory object, but a simple mock which means that its real code will not be called. Take a look at #Spy and consider replacing #Mock with it. Find more information in the following articles:
https://medium.com/swlh/what-is-the-difference-between-a-mock-and-a-stub-bd6b639e9fa5
https://www.baeldung.com/mockito-annotations#mock-annotation
in first step we must replace #Mock to Spy
and then we must change in when() method to when(spyInstance.method) and then we need called method has spyInstance.method to testing
this is my code after fixed you can see it
#Spy
InMemory inMemoryGet; // replace it from mock to spy
#InjectMocks
UserService userService;
#Before
public void init(){
MockitoAnnotations.initMocks(this);
}
#Test
public void registry(){
UserDto emp = new UserDto(1L,"Lokesh","Gupta",25); // add it
when(inMemoryGet.save(emp.ToDTO(emp))).thenReturn(emp.ToDTO(emp));
verify(inMemoryGet, times(0)).save(emp.ToDTO(emp)); // how many time invoke
userService.registry(emp); // called method from here
verify(inMemoryGet, times(1)).save(emp.ToDTO(emp));
System.out.println("\"Test\" = " + "Pass");
}
Related
Is it possible to clone an instance of a Spring #Controller in a JUnit 5 test?
I would like to do so for the following reasons :
Mocking pollutes the context for next tests and DirtiesContext has a huge impact on performance. So I don't want to use Mocks unless the modification sticks to the test class.
I would like to run tests in parallel so modifying a shared controller instance at runtime (with ReflectionUtils for example) will produce unpredictable behavior.
I don't want to set a controller as prototype as it is not the case at runtime and Spring is already wiring all dependencies.
I was thinking to inject the controller in the test class with #Autowired as usual and then making a deep copy of it with SerializationUtils like described in this post but I hope there could be a more robust approach than serializing / deserializing in every test class.
What makes tests failing in parallel mode?
The end-to-end tests are using common services. For example, I have a controller used in those two tests.
#RestController
#RequestMapping("/api/public/endpointA/")
public class SomeController {
#Autowired
private MyService myService;
#GetMapping("/{id}")
public Something getSomethingById(#PathVariable int id) {
return myService.getSomethingById(id);
}
}
The first test just check the standard usage.
class SomeControllerTest {
#Autowired
#InjectMocks
private SomeController someController;
#Test
void testGetSomethingById() {
Assertions.assertEquals(
1,
// I use some custom wrapper for the HTTP methods calls on
// the controller like this to ease the mock mvc setup.
someController.getAndParse(
HttpStatus.OK,
Something.class,
"/{id}",
1
).getId()
);
}
}
The second case test what happens when error occurs.
class SomeControllerExceptionTest {
#Autowired
private SomeController someController;
#SpyBean
private MyService myService;
#BeforeEach
public void before() {
// Mock to test error case
doThrow(RuntimeException.class).when(myService)
.getSomethingById(anyInt());
}
#Test
void testGetSomethingById() {
Assertions.assertThrows(
someController.getAndParse(
HttpStatus.OK,
Something.class,
"/{id}",
1
)
);
}
}
By mocking in the second test, I'm not sure the first test won't use the mocked instance of the second test when tests are running in parallel.
Instantiate the controller in the test method yourself, mock the dependencies inside the method and inject them in the controller.
Same situation described above but I mock on a new instance of the controller.
#RestController
#RequestMapping("/api/public/endpointA/")
public class SomeController {
#Autowired
private MyService myService;
#GetMapping("/{id}")
public Something getSomethingById(#PathVariable int id) {
return myService.getSomethingById(id);
}
}
Test both cases in one test.
class SomeControllerTest {
#Autowired
private SomeController someController;
private SomeController someControllerMocked;
#BeforeEach
public void before() {
someControllerMocked = new SomeController();
MyService mockedService = mock(MyService.class);
doThrow(RuntimeException.class).when(mockedService)
.getSomethingById(anyInt());
ReflectionTestUtils.setField(
someControllerMocked,
"myService",
mockedService
);
}
#Test
void testGetSomethingById() {
Assertions.assertEquals(
1,
someController.getAndParse(
HttpStatus.OK,
Something.class,
"/{id}",
1
).getId()
);
}
#Test
void testGetSomethingByIdException() {
Assertions.assertThrows(
someControllerMocked.getAndParse(
HttpStatus.OK,
Something.class,
"/{id}",
1
)
);
}
}
Yes! It's working and the context is not polluted. Ok let's say I have 10 services injected in my controller actually. I will have to do ReflectionUtils#setField 9 times for the legacy services and 1 time for the mock. Looks a bit ugly.
With AutowireCapableBeanFactory to the rescue. I've managed to clean this a little bit.
Same situation, but SomeController has 10 autowired services.
class SomeControllerTest {
#Autowired
private SomeController someController;
private SomeController someControllerMocked;
#Autowired
private AutowireCapableBeanFactory beanFactory;
#BeforeEach
public void before() {
someControllerMocked = new SomeController();
// Replace the 9 ReflectionUtils#setField calls with this
beanFactory.autowireBean(someControllerMocked);
MyService mockedService = mock(MyService.class);
doThrow(RuntimeException.class).when(mockedService)
.getSomethingById(anyInt());
ReflectionTestUtils.setField(
someControllerMocked,
"myService",
mockedService
);
}
#Test
void testGetSomethingById() {
Assertions.assertEquals(
1,
someController.getAndParse(
HttpStatus.OK,
Something.class,
"/{id}",
1
).getId()
);
}
#Test
void testGetSomethingByIdException() {
Assertions.assertThrows(
someControllerMocked.getAndParse(
HttpStatus.OK,
Something.class,
"/{id}",
1
)
);
}
}
I think it's the best approach I've found.
My question is how to mock
jdbcTemplate.getJdbcTemplate().execute("TRUNCATE table TABLE_1");
method?
It's return value is void if I am right.
#RunWith(MockitoJUnitRunner.class)
public class Test {
#Mock
private NamedParameterJdbcTemplate jdbcTemplate;
...
//I tried this but of course it doesn't work
doReturn(void).when(jdbcTemplate).getJdbcTemplate().execute("TRUNCATE TABLE TABLE_1");
Any help is welcome.
From the comments, my understanding is that getJdbcTemplate is not final and you're interested in mocking its return value so you can verify method calls.
Here's the approach I'd take:
// create a mock for the return value
#Mock
JdbcTemplate template;
// create a mock for the factory
#Mock
NamedParameterJdbcTemplate jdbcTemplate;
#Before
public void setUp() {
// other initializations here
// configure the factory to return the above mocked template
when(jdbcTemplate. getJdbcTemplate()).thenReturn(template);
}
Now you should be able to verify on the template mock:
verify(template).execute("TRUNCATE TABLE TABLE_1");
I have created an interface Client with its two concrete implementations
clientA and clientB and annotated them with my custom annotation.
public interface Client{
public void dosomething();
}
#Component
#Myannotation
public class clientA implements Client {
public void doSomething(){
sysout("Client A do something");
}
}
#Component
#Myannotation
public class clientB implements Client {
public void doSomething(){
sysout("Client B do something");
}
}
Now I am calling the overriden methods of both clientA and clientB from Alien class.
#Component
class Alien{
#Autowired
private ApplicationContext context;
public void performOperation(){
Map<String, Object> beans =
context.getBeansWithAnnotation(MyAnnotation.class);
for(Map.Entry<String, Object> entry: beans.entrySet()) {
Client c = (Client)entry.getValue();
c.doSomething();
}
}
}
I am facing problem with writing test method for performOperation.
#RunWith(MockitoJUnitRunner.class)
class AlienTest
{
#InjectMocks
Alien a;
#Test
public void testperformOperation(){
//how to Mock for beans
assertEquals(expected, a.performOperation());
}
}
1) How should I write testperformOperation method(allowed to change the return type of performOperation method from void to any other type)
2) Is there any better way to get list of all implementations for Client interface without creating custom annotations.
I would suggest you first refactoring Alien to make it more testable using Dependency Injection idea which its dependencies (i.e Client) can be injected from outside rather than hard coded inside a method which always get from the spring context:
#Component
public class Alien{
private List<Client> clients = new ArrayList<>();
#Autowired
public Alien(List<Client> clients) {
this.clients = clients;
}
public void performOperation(){
for(Client c: clients) {
c.doSomething();
}
}
}
If you simply want to inject all Client implementation to the Alien , you just need to #Autowired List<Client> into Alien which Spring will already help you to inject all the Client implementation to it out of the box. No need to create #Myannotation
Once you make the Alien 's dependencies injectable (i.e a list of client) , you can simply inject a mock to it and verify performOperation() really invoke all of Client 's doSomething():
#RunWith(MockitoJUnitRunner.class)
class AlienTest{
#Mock
private Client mockClientA;
#Mock
private Client mockClientB;
#Test
public void testperformOperation(){
List<Client> clients = new ArrayList<>();
clients.add(mockClientA);
clients.add(mockClientB);
Alien alien = new Alien(clients);
alien.performOperation();
verify(mockClientA).doSomething();
verify(mockClientB).doSomething();
}
}
I’ll answer both parts of your question, but I believe the first approach is inferior and the second is the go-to approach.
If you want to stick with your custom annotation approach, you need to have a #Mock ApplicationContext applicationContext in your test class. In the test method (or setup method) you need to mock the call to applicationContext.getBeansWithAnnotation and return an appropriate map containing your bean (possibly also a mock)
You can easily inject all beans to a class by injecting a List of the appropriate type. In your case
get rid of #Autowired ApplicationContext
add an #Autowired List (or, preferably, use constructor injection)
This will also make the tests simpler, no need to mock ApplicationContext.
For example, see https://dzone.com/articles/load-all-implementors
I have one repository class which which implements CrudRepository. Then in service class I have auto wired this repositary. Then in controller class I have autowired this service.
I want to write test cases of controller Class. I am using below configuration.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class XYZControllerTest {
MockMvc mockMvc;
#Mock
private XYZController xyzController;
#Autowired
private TestRestTemplate template;
#Autowired
XYZRepository xyzRepository;
#Before
public void setup() throws Exception {
mockMvc = MockMvcBuilders.standaloneSetup(xyzController).build();
}
#Test
public void testPanelShouldBeRegistered() throws Exception {
HttpEntity<Object> xyz = getHttpEntity("{\"name\": \"test 1\", \"email\": \"test10000000000001#gmail.com\","
+ " \"registrationNumber\": \"41DCT\",\"registrationDate\":\"2018-08-08T12:12:12\" }");
ResponseEntity<XYZ> response = template.postForEntity("/api/xyz", xyz, XYZ.class);
}
}
My problem is that when I run test case, data is going to insert in DB which is used for application. Can I test it without inserting data in DB.
Conceptually when we are testing services we mock repositories instead of injection.
You need to mock your repository and setup behavior for returning data.
An example :
#MockBean
XYZRepository xyzRepository;
#Test
public void test() {
// other mocks
//
when(xyzRepository.findAll()).thenReturn(Arrays.asList(new XYZ()));
// service calls
// assertions
}
I have the following service:
#Service
public class PlayerValidationService {
#Autowire
private EmailService emailService;
public boolean validatePlayerEmail(Player player) {
return this.emailService.validateEmail(player.getEmail());
}
Now in my junit test class i'm using a different 3rd service that uses PlayerValidationService :
public class junit {
#autowire PlayerAccountService playerAccountService ;
#Test
public test() {
this.playerAccountService .createAccount();
assertAllSortsOfThings();
}
Is it possible to mock the EmailService within the PlayerAccountService when using annotation based autowiring? (for example make the mock not checking the validation of the email via the regular email provider we work with)
thanks.
There are a couple of ways in which you could do this. First the simplest option is to ensure that your service provides a setEmailService(EmailService) method. In which case you just replace the Spring-injected implementation with your own.
#Autowired
private PlayerValidationService playerValidationService;
#Mock
private EmailService emailService;
#Before
public void setup() {
initMocks(this);
playerValidationService.setEmailService(emailService);
}
A shortcoming of that approach is that an instance of the full-blown EmailService is likely to be created by Spring. Assuming that you don't want that to happen, you can use 'profiles'.
In your test packages, create a configuration class which is only active in a particular profile:
#Configuration
#Profile("mockemail")
public class MockEmailConfig {
#Bean(name = "emailService")
public EmailService emailService() {
return new MyDummyEmailService();
}
}
And add an annotation to your test to activate that profile:
#ActiveProfiles({ "mockemail" })
public class PlayerValidationServiceTest {
//...
}