JUnit test Custom exception that throws #httpStatus - java

I would like to test that my custom exception is thrown when I call a method like that:
private MyObject queryDatabase(String request, String end){
HttpEntity myEntity = new NStringEntity(request, ContentType.APPLICATION_JSON)
Response response = restClient.performRequest("GET", end,Collections.emptyMap(), myEntity)
MyObject myObject = mapper.readValue(response.getEntity().getContent(), MyObject.Class);
if(myObject.getFunctions().isEmpty()){
throw new EmptyResultException("Empty result");
}
return myObject;
}
My EmptyResultException Class :
#ResponseStatus(value=HttpStatus.NO_CONTENT)
public Class EmptyResultException() extends RuntimeException(){
...
}
I'm just starting with JUnit and I have tried :
#Mock MyService myservice;
#Test(expected=EmptyResultException.class)
public void shouldReturnException() {
when(myService.queryDatabase(anyString(),anyString())).thenReturn(new MyObject());
}
It's not working. The behavior I want to try is in private method. It seems I should use Powermock for such cases. However, I have read it is not good to test private method so I would like to change my method to public. Any help please?
EDIT : My full implementation :
I have a Restcontroller :
#RestController
#RequestMapping...
public class MyController {
#Autowired
MyService myService;
#RequestMapping...
public MyObject findObject(#Valid DtoParameters parameters){
return myService.executeQuery(parameters);
}
}
And in myService Class :
#Service
public class MyService{
public MyObject executeQuery(DtoParameters parameters){
return
queryDatabase(parameters.buildRequest(),parameters.buildEnd());
}
}

If your class under test is MyService, it shouldn't have a #Mock.
I don't know your whole implementation, but let's assume MyService have injected dependencies (like your mapper)
First I would mock the mapper and inject it in MyService:
#Mock
private ObjectMapper mapper;
#InjectMocks
private MyService myService;
For this to work, your test class need to use the mockito runner. You can annotate your class with this:
#RunWith(MockitoJUnitRunner.class)
The mocks will be injected into MyService.
Now you can mock your mapper to return an empty object:
when(mapper.readValue(any(),any())).thenReturn(new MyObject());
myService.queryDatabase("request", "end")
when calling queryDatabase, this should call the mock inside.
If you were trying to test your rest controller, it is a different way. What I suggested is a unit test on MyService. If you want to test the controller, you should do it with a SpringRunner, SpringBootTest and MockMvc. But first, unit test your service, and add other tests on your controller later. For the controller, you would annotate MyService with #MockBean and throw, or Autowire it and #MockBean the mapper inside to return an empty object like the unit test.
Check this: https://spring.io/guides/gs/testing-web/
old answer:
You could change your method to protected, assuming your test is in the same package as the class you are testing, you will be able to mock it.
To mock your method, you need to write it like this:
when(myService.queryDatabase(anyString(),anyString())).thenThrow(EmptyResultException.class);
You forgot to use the when method to wrap your call.

Related

How to mock methods which has defined/fixed/hardcoded input?

I have a method in a class lets say doStuff which calls another method of another class execute:
#Component
class A {
#Autowired
B b;
int doStuff(){
return b.execute(1);
}
}
#Component
class B {
int execute(int i){
return i;
}
}
Now when I'm trying to mock the method execute, it is throwing nullPointer
#ExtendWith(MockitoExtension.class)
public class ATest{
#InjectMocks
A a;
#Mock
B b;
#Test
doStuffTest(){
when(b.execute(anyInt()).thenReturn(1);
assertEquals(1,a.doStuff());
}
}
It is throwing NullPointer Exception on line when(b.execute(anyInt()).thenReturn(1);
#Autowired annotation is part of Spring, while #Mock is part of Mockito. #Autowired will not be triggered using the Mockito test. Mocked class has to be a constructor where object can be injected by #InjectMock.
If you want to use #Autowired you need a Spring context like #SpringBootTest or others that scan and configuration your project. So, if you would like to mock this bean, you will have to #MockBean annotation.
Issue resolved with #RunWith(MockitoJUnitRunner.class) annotation, without that it's failing

Spring injecting an initiallized mock via constructor

I have a singleton class (so private constructor) which needs to use a Spring Data repository during initialization. I have one injected as a constructor argument. Roughly:
#Controller
public class MyClass {
#Autowired
private MyClass(MyRepository repo) {
repo.findAll();
}
}
I want to unit test my class, so I need to have a mock repository initialized with mock values and then passed into my class before my class is initialized. How do I write my Mockito mocks in my JUnit test to make this possible?
You don't need Spring; this is an advantage of constructor injection. Just use MyRepository mockRepo = mock(MyRepository.class) and new MyClass(mockRepo).
(Your constructor should be public, by the way. You seem to be making the common mistake of confusing different senses of "singleton"; in the case of DI it simply means that the container only makes a single instance and shares it. Finally, if you only have one constructor you don't need #Autowired.)
Unit test should be independent. It means, we are not using real data from database even call any service from our test file.
Assuming you are using JUni5 and have findAllStudents() in your controller. So your test file approximately like this
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class MyClassTest {
#Mock
private MyRepository repo;
#InjectMocks
private MyClass controller;
#BeforeAll
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testDataIsExist() {
List<String> expectednames = new ArrayList();
expectedNames.add("Foo");
expectedNames.add("Bar");
Mockito.when(myRepo.findAll()).thenReturn(expectedNames);
List<String> result = controller.findAllStudents();
Assertions.assertNotNull(result);
Assertions.assertEquals(expectednames, result);
}
}
So we are mock all the services we use in controller, then inject to controller itself. Then inside the test method we mock repo.findAll() to return expectedNames so if the controller find that function it will return what mock says to return.
After we call the function, we have to make it sure that the result is according to what we expected.
There is little value in a "unit test" for a #Controller implementation. If you use #WebMvcTest, then you can use #MockBean:
#WebMvcTest
class MyControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private MyRepository repository;
#Test
void testSomething() {
mockMvc.perform( ... );
}
}

Feign client unit test

I would like to know what is the best way to write unit tests in this context :
MyApi :
#RestController
public class MyApi{
#Autowired
MyAction myAction;
#PostMapping
public ResponseEntity addAction(#ResponseBody MyDto myDto){
return myAction.addAction(myDto);
}
}
MyAction :
#Service
public class MyAction{
#Autowired
private MyClient myClient;
public ResponseEntity<AuthenticationResponseDto> login(MyDto myDto{
return ResponseEntity.ok(myClient.addClient(myDto));
}
}
For example, is it mandatory to add constructor ?
Thanks
It's considered a good practice to use constructor injection, however if you don't want to use it you need to use #Mock and #InjectMocks. It uses reflection and constructor is not required to be defined.
#RunWith(MockitoJUnitRunner.class)
public class Test {
#Mock
private Client client;
#InjectMocks
private ServiceImpl plannerService = new ServiceImpl();
#Test
public void test() throws Exception {
....
}
}
I'm sure there is a way to avoid using an autowired constructor and just autowiring a field, however I use constructors as I consider it a good practice. It also makes it easy to inject a mocked object like so
#Mock
MyAction myAction;
MyApi myApi;
ResponseEntity<AuthenticationResponseDto> testResponse = ResponseEntity.ok
(new AuthenticationResponseDto());
#Before
public void setup(){
myApi = new MyApi(myAction);
}
#Test
public void simpleMyApiTestExample (){
when(myAction.login(any())).thenAnswer(i-> testRespone);
ResponseEntity<?> actualResponse = myApi.addAction(new MyDto());
assertThat(actualResponse).isSameAs(testResponse);
}
Just to give you an idea. I just wrote this example in the SO text editor, so appologies for any typos/mistakes. But hopefully this shows why having constructors is useful for testing things that are autowired. It allows you to mock the objects necessary for instantiation by adding them to the constructor. In this example this would probably also apply to MyDto and AuthenticationResponseDto objects as well.

Mockito: mocking a method of same class called by method under test when using #InjectMocks

I have a class I want to test that has several external dependencies, and a couple internal methods. I would like to write a test for MethodA, but not have Method A's internal call to MethodB to actually exercise MethodB. I'd like to mock/stub MethodB and return something specific instead. Usually I'd use when/thenReturn but it doesn't behave like I expect - it actually jumps into Method B while creating the mock itself.
MyService.java
#Service
public class MyService {
#Autowired
private ServiceA serviceA;
#Autowired
private ServiceB serviceB;
public SomeObject methodA() {
// some logic using serviceA.method and serviceB.method that creates "output"
SomeObject someObject = methodB(output);
return someObject;
}
public SomeObject methodB(SomeObject someObject) {
// deep mysteries done here to someObject
return someObject
}
}
MyServiceTest.java
public class MyServiceTest {
#Mock
private ServiceA serviceA;
#Mock
private ServiceB serviceB;
#InjectMocks
private MyService myService;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public void methodATest() {
when(serviceA.method()).thenReturn(stuff);
when(serviceB.method()).thenReturn(otherStuff);
// here is what I would like to do
when(myService.methodB()).thenReturn(mockedSomeObject); //<- doesn't work
assertThat(myService.methodA().getSomeObjectProperty())
.isEqualTo("property");
}
}
I've looked at solutions that manually mock the MyService class with Mockito.mock(MyService.class), but (as the above example is obviously contrived) my actual class has quite a few external dependencies and I'd prefer a solution that still allows me to mock the service using #Mock for the #Autowired dependencies and #InitMocks for the class under test, unless it's simply not possible.
I've tried:
Mockito.doReturn(mockedSomeObject).when(myService.methodB(any(SomeObject.class));
but that also steps into MethodB when creating the mock for that method, which shouldn't be happening.
Thanks in advance for the help!
Try Adding #Spy to your InjectMocks and use the object to "expect" them in a slightly different syntax.
import org.mockito.Spy;
#InjectMocks
#Spy
private MyService myService;
And now mock the service call
Mockito.doReturn(mockedSomeObject).when(myService).methodB();
Also change the other mock call to this
Mockito.doReturn(stuff).when(serviceA).method();
Mockito.doReturn(otherStuff).when(serviceB).method();
You need to mark your object as Spy or explicitly create a Spy object for it using MyClass objA=null;
MyClass spy_objA=Powermockito.spy(objA)
doReturn(what_you_want).when(spy_objA).method()
Edit: Can find a similar question you may want to check
How to mock another method in the same class which is being tested?

How to mock a private dao variable?

I have a dao.create() call that I want to mock when testing a method.
But I am missing something as I'm still getting NPE. What is wrong here?
class MyService {
#Inject
private Dao dao;
public void myMethod() {
//..
dao.create(object);
//
}
}
How can I mock out the dao.create() call?
#RunWith(PowerMockRunner.class)
#PrepareForTest(DAO.class)
public void MyServiceTest {
#Test
public void testMyMethod() {
PowerMockito.mock(DAO.class);
MyService service = new MyService();
service.myMethod(); //NPE for dao.create()
}
}
You are not injecting the DAO. With mockito you can change your test class to use #InjectMocks and use mockito runner.
#RunWith(MockitoJUnitRunner.class)
public void MyServiceTest {
#Mock
private Dao dao;
#InjectMocks
private MyService myService;
...
}
You can read more about InjectMocks at Inject Mocks API
Simpler way is changing your injection to injection by constructor. For example, you would change MyService to
class MyService {
...
private final Dao dao;
#Inject
public MyService(Dao dao) {
this.dao = dao;
}
...
}
then your test you could simple pass the mocked DAO in setup.
...
#Mock
private Dao dao;
#Before
public void setUp() {
this.dao = mock(Dao.class);
this.service = new MyService(dao);
}
...
now you can use verify to check if create was called, like:
...
verify(dao).create(argThat(isExpectedObjectBeingCreated(object)));
}
private Matcher<?> isExpectedObjectBeingCreated(Object object) { ... }
Using injection by constructor will let your dependencies clearer to other developers and it will help when creating tests :)
You still need to set the dao field with your mock.
You can use reflection to this.
You need to inject/set the mocked object DAO in your service class.
If it is a spring based project, you may have a look # Spring Junit Testrunner
If you use new MyService() the Dao is never injected. For the Dao to be injected you need to load the MyService via an ApplicationContext (Spring) or an Injector (Guice). Like you would in your normal application.
As others have already said, you need to set the dao field in your MyService class in some fashion. I'm unsure the mechanism to allow for a compound runner on your test to use both Powermock and a DI framework runner (assuming Powermock is required), but as long as you're already using PowerMock (for reasons unclear in the given example), you could avail yourself of the Whitebox class to set the dao more manually.
public void testMyMethod() {
Dao dao = mock(Dao.class)
doNothing().when(dao).create(anyObject())); //assuming no return val for dao.create()
MyService service = new MyService();
Whitebox.setInternalState(service, "dao", dao);
service.myMethod();
}

Categories