Spring Boot Test - Mockito - Service call return null - mockito

I'm testing a post method in my controller that only return a String and using Mockito to mock the service call. My problem is that when the service method is called on controller it return null.
#RunWith(SpringRunner.class)
#WebMvcTest(ProcessGroupController.class)
public class ProcessGroupRestControllerTest {
.............
#Test
public void givenAllNifiArguments_whenImportProcessGroup_thenReturnJsonOk() throws Exception {
NiFiArguments niFiArguments = NiFiArguments.builder()......flowVersion("3").build();
String expected = "1689d61b-624d-4574-823d-f1b4755882e1";
String json = mapper.writeValueAsString(niFiArguments);
//Mock service call
when(nifiService.importProcessGroup(niFiArguments)).thenReturn(expected);
mvc.perform(post("/nifi/pg-import").contentType(MediaType.APPLICATION_JSON).content(json))
.andExpect(status().isCreated())......);
}
The controller:
#PostMapping("/pg-import")
public ResponseEntity<String> importProcessGroup(#RequestBody NiFiArguments niFiArguments)
throws NiFiClientException {
log.info("Called method importFlow");
String result = nifiService.importProcessGroup(niFiArguments);
return new ResponseEntity<String>(result, HttpStatus.CREATED);
}
String result = null
I have similar tests that return a POJO and it works perfectly

As ekalin said my builder class needed to implement equals and hashcode:
#Builder
#Getter
#EqualsAndHashCode
public class NiFiArguments {
private String bucketIdentifier;
private String flowIdentifier;
private String flowVersion;
private String baseUrl;
}

Related

How to create mockito unit tests in functions that use Mutiny.Session

After some investigation I continue to pursue a more intuitive way to mock Mutiny.Session and test my functionality.
Here the method I want to test:
public class ServiceCrud {
#Inject
Mutiny.SessionFactory mutinySessionFactory;
#Inject
MicroserviceService service;
public Uni<Service> get(#NotNull final String identifier) throws ConstraintViolationException, NotFoundException {
return mutinySessionFactory.withSession(session -> {
EntityGraph<Service> entityGraph = session.getEntityGraph(Service.class, "exampleEntityGraph");
return service.get(identifier)
.onItem().ifNull().failWith(NotFoundException::new)
.onItem().transformToUni(
microservice -> Uni.createFrom()
.item(new Service(microservice.getMsId(), microservice.getMsName())));
});
}
}
The only way I found to test was through the argument captor:
#ExtendWith(MockitoExtension.class)
public class ServiceCrudTest {
#InjectMocks
private ServiceCrud serviceCrud;
#Mock
Mutiny.SessionFactory mutinySessionFactory;
#Mock
MicroserviceService service;
#Captor
ArgumentCaptor<Function<Session, Uni<Service>>> captor;
#Mock
Session session;
#Mock
EntityGraph<Service> entityGraph;
#Test
void getTest() {
// data
String msId = "msid";
String msName = "name";
Microservice toBeReturned = new Microservice();
toBeReturned.setMsId(msId);
toBeReturned.setMsName(msName);
Service expected = new Service();
expected.setId(msId);
expected.setName(msName);
// expectation
doReturn(Uni.createFrom().item(toBeReturned))
.when(service).get(anyString());
doReturn(entityGraph).when(session)
.getEntityGraph(Mockito.eq(Service.class), Mockito.anyString());
// action
serviceCrud.get("");
// capture the function and invoke it
Mockito.verify(mutinySessionFactory).withSession(captor.capture());
Function<Session, Uni<Service>> value = captor.getValue();
Uni<Service> callback = value.apply(session);
UniAssertSubscriber<Service> subscriber = callback
.subscribe().withSubscriber(UniAssertSubscriber.create());
subscriber.assertCompleted().assertItem(expected);
}
}
Is it the only way to test? Is this the correct way to test?
Any tips will be appreciated

How to mock or prepare test methods in case we called private method inside the method?

While writing a testCase for Controller class,The private method that is getServiceContext(). has different object because
one we are passing serviceContext from testclass and other object inside the controller class itself call itself.Due to this Foo object is null. how to resolve this.
public class Controller {
#Refernce
private FooService fooService;
public CustomData getDetails(String id){
Foo foo = fooService.getFoo(id ,**getServiceContext()**);
//getServiceContext() is different object
System.out.println("foo data>>>> "+foo); // **Throwing null pointer exceptions**
CustomData customData = new CustomData();
customData.setStudentName(foo.getName);
customData.setStudentName(foo.getId);
...
...
...
return customData;
}
private ServiceContext getServiceContext() {
ServiceContext serviceContext = new ServiceContext();
serviceContext.setCompanyId(context..);
serviceContext.setUserId(context..);
...
....
retrn serviceContext;
}
}
public class ControllerTest {
#InjectMocks
private Controller controller;
#Mock
private FooService fooService;
private Foo foo;
#BeforeEach
public void setUp() throws PortalException {
foo = mock(Foo.class);
}
#Test
public void getDetailsTest() throws Exception {
ServiceContext **serviceContext** = new ServiceContext();
serviceContext.setCompanyId(context..);
serviceContext.setUserId(context..);
...
....
Mockito.when(fooService.getFoo("testId",serviceContext)).thenReturn(foo);
System.out.println("Service context>>>> "+**serviceContext**); // different serviceContext object
CustomData customData = controller.getDetails("testId");
Assertions.assertThat(ss).isNotNull();
}
}
There are multiple ways to do that.
First, we can mock with anyOf(Type.class), that will actually match object type rather than value.
Mockito
.when(fooService.getFoo(Mockit.eq("testId"), Mockito.any(ServiceContext.class)))
.thenReturn(foo);
this will work as expected and return the desired value.
Additionally, if you want to check with what data serviceContext object is being passed as arg in service method, (as we just checked object type rather than value), We can use ArgumentCaptor for that.
It basically captures argument data which is being passed in the method call.
let's create ArgumentCaptor for service context
#Mock
private FooService fooService;
#Captor
private ArgumentCaptor<ServiceContext> captor;
Now, let's capture the argument during verification.
Mockito.verify(fooService).getFoo(Mockit.eq("testId"), captor.capture());
Assertions.assertEquals("value of x in context", captor.getValue().getX());
Basically here, captor.getValue() returns service context object which is being passed. So, you can verify all data you want to validate in that object.
Alternate, Approach would be Spy which will basically spy on the class under test and you can control the behavior of private methods in test class itself.
To do that, we need to add #Spy annotation along with #InjectMocks on test class.
#Spy
#InjectMocks
private Controller controller;
Now, you can mock the private method and return the expected value.
Mockito.doReturn(serviceContextValue).when(controller).getServiceContext();
and use that object for mocking fooService.
Mockito.verify(fooService).getFoo("testId", serviceContextValue);
But when using Spy, don't forget to write unit test for private method as it's mocked, it's business logic will not be tested by above test cases. that's a reason, it's not recommended way.
I would suggest using ArgumentCaptor approach.

Mockito, channel output of void function to System.out?

I have this logging class in my legacy application,
I am trying to Mock it for testing and output all messages from "WriteLog" method to System.out
This is the class
public abstract class LoggingServicesWorker {
public abstract void WriteLog(ELogLevel arg0, int arg1,String arg2,String arg3);
}
This is what I did so far,
I am not sure how to write to System.out
Also How to tell the first argument to have any enum type (ELogLevel)?
LoggingServicesWorker logger = mock(LoggingServicesWorker.class);
Mockito.doNothing().when(logger).WriteLog(ELogLevel.DEBUG,anyInt(),anyString(),Mockito.eq(anyString()));
You can use Mockito#doAnswer for executing side-effects:
doAnswer((invocation -> {
System.out.println(Arrays.toString(invocation.getArguments()));
return null;
}))
.when(worker)
.WriteLog(any(ELogLevel.class), anyInt(), anyString(), anyString());
Standalone class with the default behavior for return values (and usable with Java 7):
class PrintArgsToStdoutAnswer implements Answer<Object> {
private final ReturnsEmptyValues defaultReturn = new ReturnsEmptyValues();
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
System.out.println(Arrays.toString(invocation.getArguments()));
return defaultReturn.answer(invocation);
}
}
...and used in the test method:
doAnswer(new PrintArgsToStdoutAnswer())...

MockMvc fails because of method invocation inside the controller method

I try to mock a controller which contains a util method inside even though I mock the util method, the mvcMock ignore the result from the when(...) and call the method again with empty parameters which lead to nullpointerexception
How I can ship the call of
when(utilMock.getOperatorsAdNameWrapper(userName, adNames)).thenReturn(roleSet);
with the mockMvc.perform?
#GetMapping(value = {"/wellbore"})
public String wellboreForm(Model model, #RequestParam("mode") String mode, HttpServletRequest request) {
Set<String> operators = new LinkedHashSet<>();
String userName = (String) request.getSession().getAttribute("userName");
Set<String> operatorsSet = (HashSet<String>) request.getSession().getAttribute("userRoles");
Set<String> operatorsAdName = util.getOperatorsAdNameWrapper(userName, operatorsSet);
operatorsAdName.forEach(adName -> {
Query query = new Query()
.setClassname(Wellbore.CLASS)
.eq(Wellbore.operatorsGroup, adName);
operators.addAll(getWellboresNameList(query));
});
model.addAttribute("wellboreDataList", operators);
model.addAttribute("wellboreData", new WellboreForm());
return "ui/selectWellbore";
}
public static Set<String> getOperatorsAdName(String userName, Set<String> operatorsAdName) {
operatorsAdName.removeIf(x -> x.equals(userName)
|| x.equals("SCOUT")
|| x.equals("GTO")
|| x.equals("KADME")
|| x.equals("offline_access")
|| x.equals("uma_authorization"));
return operatorsAdName;
}
public Set<String> getOperatorsAdNameWrapper(String userName, Set<String> operatorsAdName) {
return getOperatorsAdName(userName,operatorsAdName);
}
#Mock
private Util utilMock;
#Test
#DisplayName("GET /wellbore - Select Wellbore")
void testMockMvc() throws Exception {
HttpServletRequest req = Mockito.mock(HttpServletRequest.class);
when(req.getAttribute("userName")).thenReturn("abcd");
String userName = (String) req.getAttribute("userName");
//Here I get the correct result Result
when(utilMock.getOperatorsAdNameWrapper(userName, adNames)).thenReturn(roleSet);
//another call made here with empy parameters to utilMock.getOperatorsAdNameWrapper("", null)
mockMvc.perform(get("/wellbore").param("mode","selectWellbore")
.sessionAttr("wellboreDataList", new LinkedHashSet<>())
.sessionAttr("wellboreData", new WellboreForm())
)
.andExpect(status().isOk())
.andExpect(view().name("ui/selectWellbore"))
.andExpect(model().attribute("wellboreDataList", hasSize(2)));
}
1) In the Controller move the line:
util.getOperatorsAdNameWrapper(userName, operatorsSet);
into a package level method:
Set<String> getOperatorsAdNameWrapper(userName, operatorsSet){
return util.getOperatorsAdNameWrapper(userName, operatorsSet);
}
2) In your test use SpyBean:
#SpyBean
private Controller controllerSpy;
#Test
#DisplayName("GET /wellbore - Select Wellbore")
void testMockMvc() throws Exception {
doReturn(roleSet).when(controllerSpy).getOperatorsAdNameWrapper(userName, adNames);
The general gist is that you cannot mock a static call with vanilla Mockito. You have to refactor a bit first.
The Problem was with the Util class
since I am using mockmvc as unit testing, not as integration test by standaloneSetup
mockMvc = MockMvcBuilders
//To avoid loading springContext
.standaloneSetup(controller)
.setViewResolvers(viewResolver())
.build();
so the Util class not loaded to the context to solve this you have to option
Move the wrapper method in the util class to the service class and from there you can wrapper the static method in the Util class
Add the util class to the controller constructor

Using Mockito for writing ATG test case

Does anyone have idea about writing unit test case for ATG using Mockito? I came across following discussions while goggling -
Automated unit tests for ATG development and
Using PowerMock to obtain the ATG Nucleus in testing results in NPE
But need a help in setting up Nucleus and other dependencies (DAS, DPS, DSS etc.) and a sample test class for droplet using Mockito.
We are using ATG Dust where we have to set all the dependencies. I am wondering if we can replace ATG Dust completely with Mockito. Here is the example how we are writing the test cases -
A Base class for setting Nucleus -
package com.ebiz.market.support;
import java.io.File;
import java.util.Arrays;
import atg.nucleus.NucleusTestUtils;
import atg.test.AtgDustCase;
import atg.test.util.FileUtil;
public class BaseTestCase extends AtgDustCase {
public atg.nucleus.Nucleus mNucleus = null;
private final String ATGHOME="C://ATG/ATG9.4//home";
private final String ATGHOMEPROPERTY = "atg.dynamo.home";
protected void setUp() throws Exception {
super.setUp();
String dynamoHome = System.getProperty(ATGHOMEPROPERTY);
if(dynamoHome == null)
System.setProperty(ATGHOMEPROPERTY, ATGHOME);
File configpath = NucleusTestUtils.getConfigpath(this.getClass(), this.getClass().getName(), true);
FileUtil.copyDirectory("src/test/resources/config/test/", configpath.getAbsolutePath(), Arrays.asList(new String [] {".svn"}));
copyConfigurationFiles(new String[]{"config"}, configpath.getAbsolutePath(), ".svn");
}
public File getConfigPath() {
return NucleusTestUtils.getConfigpath(this.getClass(), this.getClass().getName(), true);
}
}
Writing the test case by extending the base class -
public class BizDropletTest extends BaseTestCase {
private BizDroplet bizDroplet;
#Before
public void setUp() throws Exception {
super.setUp();
mNucleus = NucleusTestUtils.startNucleusWithModules(new String[] { "DSS", "DPS", "DAFEAR" }, this.getClass(),
this.getClass().getName(), "com/ebiz/market/support/droplet/BizDroplet");
autoSuggestDroplet = (AutoSuggestDroplet) mNucleus.resolveName("com/ebiz/market/support/droplet/BizDroplet");
try {
bizDroplet.doStartService();
} catch (ServiceException e) {
fail(e.getMessage());
}
}
/**
Other methods
*/
}
So, how Mockito can handle these? Again, for me the target is to replace ATG Dust with Mockito completely because ATG Dust take lot of time in running tests due to huge dependencies.
Thanks.
Using Mockito you don't setup Nucleus or other dependencies (unless you need it). You simply mock the objects that you need to use.
Consider a simple class ProductUrlDroplet that retrieves a product from the repository and then outputs a url based on this. The service method would look something like this:
public void service(DynamoHttpServletRequest pRequest, DynamoHttpServletResponse pResponse) throws ServletException, IOException {
Object product = pRequest.getObjectParameter(PRODUCT_ID);
RepositoryItem productItem = (RepositoryItem) product;
String generatedUrl = generateProductUrl(pRequest, productItem.getRepositoryId());
pRequest.setParameter(PRODUCT_URL_ID, generatedUrl);
pRequest.serviceParameter(OPARAM_OUTPUT, pRequest, pResponse);
}
private String generateProductUrl(DynamoHttpServletRequest request, String productId) {
HttpServletRequest originatingRequest = (HttpServletRequest) request.resolveName("/OriginatingRequest");
String contextroot = originatingRequest.getContextPath();
return contextroot + "/browse/product.jsp?productId=" + productId;
}
A simple test class for this will then be:
public class ProductUrlDropletTest {
#InjectMocks private ProductUrlDroplet testObj;
#Mock private DynamoHttpServletRequest requestMock;
#Mock private DynamoHttpServletResponse responseMock;
#Mock private RepositoryItem productRepositoryItemMock;
#BeforeMethod(groups = { "unit" })
public void setup() throws Exception {
testObj = new ProductUrlDroplet();
MockitoAnnotations.initMocks(this);
Mockito.when(productRepositoryItemMock.getRepositoryId()).thenReturn("50302372");
}
#Test(groups = { "unit" })
public void testProductURL() throws Exception {
Mockito.when(requestMock.getObjectParameter(ProductUrlDroplet.PRODUCT_ID)).thenReturn(productRepositoryItemMock);
testObj.service(requestMock, responseMock);
ArgumentCaptor<String> argumentProductURL = ArgumentCaptor.forClass(String.class);
Mockito.verify(requestMock).setParameter(Matchers.eq(ProductUrlDroplet.PRODUCT_URL_ID), argumentProductURL.capture());
Assert.assertTrue(argumentProductURL.getValue().equals("/browse/product.jsp?productId=50302372"));
}
}
The key components are that you need to initialise the class you want to test (testObj). You then simply construct the response for each of the input parameters of the objects you are going to use (in this case productRepositoryItemMock represents the RepositoryItem and productRepositoryItemMock.getRepositoryId() returns a String that you can then test against later).
You will also notice that this test only validates the service method and not the individual methods. How you do it is up to you but generally I've been focused on testing my service and handleXXX methods in the formhandlers and droplets.
Testing the XXXManager, XXXUtil and XXXService classes will all have their own tests and should be 'mocked' into the droplets and formhandlers. For these I would write tests for each method though.
PowerMockito only really comes into the picture when you need to mock static methods and classes and the documentation does enough to explain that.

Resources