Consider:
#GetMapping(path = {"/attachment/answer/{answerId}"})
public APIResponse<List<AttachmentVM>> getAttachmentListForAnswer(#PathVariable("answerId") UUID answerId) {
List<AttachmentBO> attachmentBOList = this.attachmentService.getAttachmentListForAnswer(answerId);
List<AttachmentVM> noteVMList = super.mapList(attachmentBOList, AttachmentVM.class);
return APIResponse.ok(noteVMList);
}
How can we write a JUnit testcase for this Controller using Mockito, using Mockito.when, and then return?
If you want to test your API, I would suggest Wiremock instead of Mockito.
#Test
public void shouldGetEndpoint() {
String path = "/endpoint";
wiremock.stubFor(get(urlEqualTo(path))
.willReturn(aResponse()
.withStatus(200))
);
}
If you want to write a unit test for your class by mocking attachmentService, you will need to do something like:
List<AttachmentBO> providedList = new ArrayList<>();
MyService attachmentService = Mockito.mock(MyService.class);
when(attachmentService.getAttachmentListForAnswer(any())).thenReturn(providedList);
Check out this tutorial
I'm assuming you're using Spring Boot.
#Autowired private MockMvc mockMvc;
#MockBean private AttachmentService attachmentService;
#Test public void test() {
List<AttachmentBO> attachmentBOList = new ArrayList<>();
String answerId = "myId";
// mocking your service here by directly returning the list
// instead of executing the code of the service class
Mockito.when(attachmentService.getAttachmentListForAnswer(answerId))
.thenReturn(attachmentBOList);
// calling the controller
String url = "/attachment/answer/" + answerId;
this.mockMvc.perform(MockMvcRequestBuilders.get(url))
.andExpect(MockMvcResultMatchers.status.isOk());
Related
Here is the class and the method I am trying to unit test.
public abstract class ShowService {
#Resource(name = "blogCoreSolrClient")
private SolrClient blogCoreSolrClient;
protected Show findShow(ClientRegion clientRegion, TargetLocale locale, Integer showId) {
SolrQuery query = new SolrQuery();
query.setQuery("type:" + SolrType.show)
.addFilterQuery(getRegionQuery(clientRegion))
.addFilterQuery(getLanguageFallbackQuery(locale))
.addFilterQuery("show_id:" + showId)
.setRows(1);
QueryResponse response = blogCoreSolrClient.query(query);
List<Show> shows = response.getBeans(Show.class);
if (shows != null && shows.size() > 0) {
return shows.get(0);
}
return null;
}
public static class SyndicatedShow {
#Field("show_id")
public Integer showId;
#Field("path_value")
public String pathValue;
}
}
Here's my Unit test written using Mockito
public class ShowServiceTest {
public final QueryResponse queryResponse = Mockito.mock(QueryResponse.class);
public final SolrClient blogCoreSolrClient = Mockito.mock(SolrClient.class);
public final SolrQuery SolrQuery = Mockito.mock(SolrQuery.class);
private SolrDocumentList solrDocuments = Mockito.mock(SolrDocumentList.class);
private ShowService showService = Mockito.mock(ShowService.class);
#Test
public void findShowTest() {
Mockito.when(blogCoreSolrClient.query(solrQueryCaptor.capture())).thenReturn(queryResponse);
Mockito.when(queryResponse.getResults()).thenReturn(solrDocuments);
Mockito.when(blogCoreSolrClient.query(any())).thenReturn(queryResponse);
ShowService.Show showsResult = ShowService.findShow(ClientRegion.US, TargetLocale.EN_US, 1234);
assertThat(showsResult.pathValue).isEqualTo("shows/test/");
}
}
I am getting Null at blogCoreSolrClient when the code passes to findShow().
Because of that I am getting NullPointerException.
Any suggestions, where I might be going wrong. TIA
There are different problems :
You're mocking the class under test
private ShowService showService = Mockito.mock(ShowService.class);
You don't tell to your ShowService to use the blogCoreSolrClient mock, then the blogCoreSolrClient mock instance is created, but never used.
As you are using IOC to inject the SolrClient (#Resource annotation), you need to inject the mock in your ShowService instance during the test.
There are different solutions, but the more convenient in your case would be to use the Mockito Extension to perform the injection.
Something like :
#ExtendWith(MockitoExtension.class)
public class ShowServiceTest {
#Mock
private SolrClient blogCoreSolrClient;
... // Other mocks
#InjectMocks
private ShowService showService;
#Test
public void findShowTest() {
Mockito.when(blogCoreSolrClient.query(any())).thenReturn(queryResponse);
... // Complete test
}
}
The problem would be that your class under test is an abstract class.
I don't see any abstract method. So, if you really need the class under test to be abstract, then you'll face a technical difficulty with #InjectMocks.
Here are some solutions :
https://tedvinke.wordpress.com/2020/06/22/mockito-cannot-instantiate-injectmocks-field-the-type-is-an-abstract-class/
How to return Page content in Spring Boot Unit test service layer? How to mock this data with some values and later on test it?
Service that needs to be tested:
#Service
#RequiredArgsConstructor
#Transactional(readOnly = true)
public class CampaignReadServiceImpl02 {
private final CampaignRepository campaignRepository;
public Page<Campaign> getAll(int page, int size) {
Pageable pageable = PageRequest.of(page, size);
Page<Campaign> pages = campaignRepository.findAll(pageable);
return pages;
}
}
The class that mocks data in Unit test
#Slf4j
#ExtendWith(MockitoExtension.class)
public class CampaignReadServiceTest {
#Mock
private CampaignRepository campaignRepository;
private CampaignReadServiceImpl02 campaignReadServiceImpl02;
#BeforeEach
public void beforeEach() {
campaignReadServiceImpl02 = new CampaignReadServiceImpl02(campaignRepository);
}
#Test
public void testGetAll02() {
log.info("Testing get all campaigns method");
//this need to have content data inside of page.getContent(), need to be added
Page<Campaign> page = Mockito.mock(Page.class);
Mockito.when(campaignRepository.findAll(Mockito.any(Pageable.class))).thenReturn(page);
Page<Campaign> result = campaignReadServiceImpl02.getAll(2, 2);
Assertions.assertNotNull(result);
Mockito.verify(campaignRepository, Mockito.times(1)).findAll(Mockito.any(Pageable.class));
Mockito.verifyNoMoreInteractions(campaignRepository);
}
}
How to mock Page<Campaign> page = Mockito.mock(Page.class); to get result.getContent(); when Service repository is injected in Service..
I can't test result.getContent() because I don't have data from repository, maube because I need to change mock Page<Campaign> page with Page.class to something else?
How to properly mock Page<Campaign> page = Mockito.mock(Page.class); that will return some data later on in service: result.getContent().name(), etc..
easiest way would be to create an object instead of mocking the class.
Page<TournamentEntity> tournamentEntitiesPage = new PageImpl<>(List.of(obj1, obj2), pageable, 0);
I have a Spring #RestController that has a field of Apache Camel interface FluentProducerTemplate.
I am testing the controller with MockMvc and I am injecting FluentProducerTemplate as a mock.
I would like to mock only one method - request(), and use the real implementation of the other methods.
However, I get NullPointerException from the unmocked methods. Other FluentProducerTemplate methods n , their return type is FluentProducerTemplate. In the implementation they return this. The mock object returns null.
I thought that mockito #Mock mocks only the methods that I specify. Other methods use the original implementation. Is this a correct statement?
I tried #Spy instead of #Mock and I got the same error.
When I mock all the methods that I work with then it works and no NullPointerException.
Code:
REST Controller:
#RestController
#RequestMapping("/v1/test”)
public class MyController {
#EndpointInject(uri = "direct:main")
private FluentProducerTemplate producerTemplate;
#RequestMapping(value = “/test2”, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public MyResponse testRequest(
#RequestHeader(“id”) String id,
#RequestHeader(“context”) String context,
#RequestBody RequestBody requestBody
) {
MyResponse response = producerTemplate
.withHeader(“id”, id)
.withHeader(“context”, context)
.withBody(requestBody)
.request(MyResponse.class);
return response;
}
Test:
#RunWith(MockitoJUnitRunner.class)
public class MyControllerTest {
private MockMvc mockMvc;
#Mock
private FluentProducerTemplate producerTemplateMock;
#InjectMocks
private MyControllerTest myController;
private static MyResponse expectedResultSuccess;
private static String requestString;
private static HttpHeaders allRequestHeaders;
#BeforeClass
public static void setup() {
allRequestHeaders = new HttpHeaders();
allRequestHeaders.set(“id”, “123”);
allRequestHeaders.set(“context”, “ABCD1234”);
allRequestHeaders.set(“Content-Type”, “application/json”);
expectedResultSuccess = new MyResponse(“test”);
requestString = “request”BodyText;
}
#Before
public void init() {
mockMvc = MockMvcBuilders.standaloneSetup(myController).build();
when(producerTemplateMock.request(any())).thenReturn(expectedResultSuccess);
}
#Test
public void testSuccess() throws Exception {
mockMvc.perform(post(“/v1/test/test2)
.headers(allRequestHeaders)
.content(requestString))
.andExpect(status().isOk())
}
}
The test pass only when I add the below to init():
when(producerTemplateMock.withHeader(any(), any())).thenReturn(producerTemplateMock);
when(producerTemplateMock.withBody(any())).thenReturn(producerTemplateMock);
My main question is - why do I have to mock all methods?
I prefer to use the original implementation of withHeader() and withBody() and mock only request().
You want so called partial mocks. Depending on whether you want to set up mostly mocks or mostly call real implementations there are different prefered approaches.
1. spy for few mocks, mostly real implementation
If you want to mock only some methods and otherwise call the real implementation:
FluentProducerTemplate producerTemplateMock = spy(FluentProducerTemplate.class);
// Mock implementation
doReturn(expectedResultSuccess).when(producerTemplateMock).request(any());
// All other method call will use the real implementations
2. mock for mostly mocks, few real implementations
FluentProducerTemplate producerTemplateMock = mock(FluentProducerTemplate.class);
// Mock methods
when(producerTemplateMock.request(any())).thenReturn(expectedResultSuccess);
// tell mockito to call the real methods
when(producerTemplateMock.withHeader(any(), any())).thenCallRealMethod;
when(producerTemplateMock.withBody(any())).thenCallRealMethod();
As you can see, the 2nd approach is more boilerplate to write. However, it depends on your use case what approach is better suited.
I have tests with allure2 #Tmslink("1234") annotaion on each #Test. So, i need to get #TmsLink value and use it in my tests. I've got annotation value in extension, but how can i provide it to test?
public class TmsLink implements BeforeTestExecutionCallback {
private String tmsLink;
#Override
public void beforeTestExecution(ExtensionContext context) {
findAnnotation(context.getElement(), TmsLink.class).ifPresent(link -> this.tmsLink = link.value());
}
public String getTmsLink() {
return tmsLink;
}
}
#ExtendWith(TmsLink .class)
public abstract class Tests {
}
With Junit4 it's just:
#Rule
public TmsLink extension = new TmsLink();
extension.getTmsLink();
JUnit Jupiter also supports registering extensions programmatically by annotating fields in test classes with #RegisterExtension:
class WebServerDemo {
#RegisterExtension
static WebServerExtension server = WebServerExtension.builder()
.enableSecurity(false)
.build();
#Test
void getProductList() {
WebClient webClient = new WebClient();
String serverUrl = server.getServerUrl();
// Use WebClient to connect to web server using serverUrl and verify response
assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus());
}
}
For details please consult the User-Guide at https://junit.org/junit5/docs/current/user-guide/#extensions-registration-programmatic
Or let your extension also implement ParameterResolver and inject TmsLink as an argument to your test method parameter. Find details and an example linked at https://junit.org/junit5/docs/current/user-guide/#extensions-parameter-resolution
I want to test my controller class and its methods.
My Controller method looks like this:
#RequestMapping(value = "/updateUserStory/{usid}", method = RequestMethod.GET)
public String updateUserStory(#PathVariable("trrid") Integer trrID, #PathVariable("usid") Integer userstoryID, Model model ){
UserStory userStory = this.userStoryService.getUserStoryById(userstoryID);
model.addAttribute("userstory", userStory);
model.addAttribute("trrID", trrID);
return "updateUserStory";
}
My test method looks like this:
public void updateUserStory() throws Exception {
Model model = mockModel();
UserStory userStory = new UserStory();
userStory.setId(1);
EasyMock.expect(userStoryService.getUserStoryById(1)).andReturn(userStory);
EasyMock.replay(userStoryService);
String test = controller.updateUserStory(1, 1, model );
EasyMock.verify(userStoryService);
Assert.assertEquals("updateUserStory", test);
}
I added #Mock above for the userStoryService
#Mock
private UserStoryServiceImpl userStoryService;
and #TestSubject for the UserStoryController (In the test simply called controller).
#TestSubject
UserStoryController controller = new UserStoryController();
When running the test I keep getting A NullPointerException at the EasyMock.expect line. I don't know how this is failing. I am mocking the right method.
I see two possible reasons.
1. You haven't used any runner or rule.
To inject mocks, EasyMock needs a JUnit rule
#Rule
public EasyMockRule mocks = new EasyMockRule(this);
or a runner
#RunWith(EasyMockRunner.class)
public class MyTest {
2. The field type is UserStoryService
Not UserStoryServiceImpl. So you should mock UserStoryService instead.