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

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

Related

How do I mock both a final and a static using Mockito

So I have a couple Tests that run using mockito. One requires a static to be mocked so I use PowerMockito like this...
BDDMockito.given(WebClient.create(any())).willReturn(webClientMock);
Next I have another test that mocks a final class like this...
HttpSecurity security = Mockito.mock(HttpSecurity.class);
The second one doesn't work at first, I get the following failure....
Cannot mock/spy class org.springframework.security.config.annotation.web.builders.HttpSecurity
Mockito cannot mock/spy because :
- final class
So I looked and found this question which suggests adding the file .../src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker with mock-maker-inline
But when I add that the first line fails with...
org.mockito.exceptions.misusing.NotAMockException: Argument should be a mock, but is: class java.lang.Class
How do I get both to work?
Update
I didn't want to clutter up the question with the entire test which really doesn't provide any extra context. However, since people are insisting and seem to misunderstand the question...
// Static
#ExtendWith(MockitoExtension.class)
#RunWith(PowerMockRunner.class)
#PrepareForTest(WebClient.class)
public class RasaServiceTest {
#Mock
private WebClient webClientMock;
#Mock
private WebClient.RequestHeadersSpec requestHeadersMock;
#Mock
private WebClient.RequestHeadersUriSpec requestHeadersUriMock;
#Mock
private WebClient.RequestBodyUriSpec requestBodyUriMock;
#Mock
private WebClient.ResponseSpec responseMock;
private MyService service = new MyService();
#BeforeAll
public void setup(){
PowerMockito.mockStatic(WebClient.class);
BDDMockito.given(WebClient.create(any())).willReturn(webClientMock);
}
#Test
public void HappyPath(){
MessageResponseItem item = new MessageResponseItem();
item.setRecipientId("id");
item.setResponseText("response");
MessageResponseItem[] items = {item};
when(webClientMock.post()).thenReturn(requestBodyUriMock);
when(requestHeadersUriMock.uri("/webhooks/rest/webhook")).thenReturn(requestHeadersMock);
when(requestHeadersMock.retrieve()).thenReturn(responseMock);
when(responseMock.bodyToMono(MessageResponseItem[].class)).thenReturn(Mono.just(items));
InferenceEngineRequest request = new InferenceEngineRequest();
MessageResponseItem[] result = service.call(request).block();
assertThat(result.length).isEqualTo(1);
assertThat(result[0].getResponseText()).isEqualTo("response");
}
}
// Final
#RunWith(MockitoJUnitRunner.class)
public class RemoveMeConfigTest {
#Test
public void happyPath() throws Exception {
HttpSecurity security = Mockito.mock(HttpSecurity.class);
CsrfConfigurer<HttpSecurity> csrf = Mockito.mock(CsrfConfigurer.class);
RemoveMeConfig config = new RemoveMeConfig();
Mockito.when(
security.csrf()
).thenReturn(csrf);
Mockito.when(
csrf.disable()
).thenReturn(security);
config.configure(security);
Mockito.verify(
security,
Mockito.times(
1
)
).csrf();
Mockito.verify(
csrf,
Mockito.times(1)
).disable();
}
}

Mockito: How to test a class's void method?

Unit test noob here.
I have three classes: Db1Dao, Db2Dao, ExecuteClass where Db1Dao, Db2Dao are database access objects for two different databases. My goal is to fetch some data from db1 using Db1Dao and run executeClass.execute() to "put" the processed data into db2 using Db2Dao.
My ExecuteClass looks like this:
class ExecuteClass {
private Db1Dao db1Dao;
private Db2Dao db2Dao;
public void execute() {
...
List<String> listOfString = getExternalData(someParam);
List<Metadata> metadatum = db1Dao.get(someInputs);
... I do something to generate a list of new class `A` based on listOfString & metadatum ...
try {
db2Dao.put(listOfA);
} catch (PutException e){
...
}
}
public List<String> getExternalData(SomeClass someParam){
... do something
return listOfString;
}
}
Now I want to test:
Given a specific listOfString (returned by getExternalData) and a specific metadatum (returned by db1Dao.get):
Will I get the desired listOfA?
Am I able to call db2Dao.put and its input parameter is listOfA?
Particularly, I have hard-coded sample listOfString and metadatum and desired listOfA (and they will be passed via an object MockData, see the following code) but I don't know how to write the test using Mockito. The following is a test class I wrote but it does not work:
class TestClass extends BaseTest {
#Mock
private Db1Dao db1Dao;
#Mock
private Db2Dao db2Dao;
private ExecuteClass executeClass;
#BeforeEach
public void setUp() {
MockitoAnnotations.initMocks(this);
executeClass = new ExecuteClass(db1Dao, db2Dao);
}
#ParameterizedTest
#MethodSource("MockDataProvider")
public void executeClassTest(final MockData mockData) throws PutException {
Mockito.when(db1Dao.get(Mockito.any(), ...))
.thenReturn(mockData.getMetadatum());
ExecuteClass executeClassSpy = Mockito.spy(executeClass);
Mockito.when(executeClassSpy.getExternalData(Mockito.any()))
.thenReturn(mockData.getListOfString());
executeClassSpy.execute();
// executeClass.execute(); not working neither...
List<A> listOfA = mockData.getDesiredListOfA();
Mockito.verify(db2Dao).put(listOfA);
}
}
Could anyone please let me know? Thank you in advance!!
You should not create a spy of the same class you want to test. Instead, try to write a unit test for the smallest amount of code (e.g. a public method) and mock every external operator (in your case Db1Dao and Db2Dao).
If testing a public method involves calling another public method of the same class, make sure to mock everything inside the other public method (in your case getExternalData). Otherwise, this other public method might be a good candidate for an extra class to have clear separation of concerns.
So, remove the ExecuteClass executeClassSpy = Mockito.spy(executeClass); and make sure you setup everything with Mockito what's called within getExternalData.
To now actually, verify that Db2Dao was called with the correct parameter, either use your current approach with verifying the payload. But here it's important to 100% create the same data structure you get while executing your application code.
Another solution would be to use Mockito's #Captor. This allows you to capture the value of why verifying the invocation of a mock. Later on, you can also write assertions on the captured value:
#Captor
private ArgumentCaptor<ClassOfListOfA> argumentCaptor;
#Test
public void yourTest() {
Mockito.verify(db2Dao).put(argumentCaptor.capture());
assertEquals("StringValue", argumentCaptur.getValue().getWhateverGetterYouHave);
}
The following code worked for me.
I partially accepted #rieckpil's answer. I used #Captor which is very handy.
The reason I had to mock getExternalData() is because its implementation is still a "TODO".
class TestClass extends BaseTest {
#Mock
private Db1Dao db1Dao;
#Mock
private Db2Dao db2Dao;
#Captor
private ArgumentCaptor<List<A>> argumentCaptor;
private ExecuteClass executeClass;
#BeforeEach
public void setUp() {
MockitoAnnotations.initMocks(this);
executeClass = new ExecuteClass(db1Dao, db2Dao);
}
#ParameterizedTest
#MethodSource("MockDataProvider")
public void executeClassTest(final MockData mockData) throws PutException {
Mockito.when(db1Dao.get(Mockito.any(), ...))
.thenReturn(mockData.getMetadatum());
ExecuteClass executeClassSpy = Mockito.spy(executeClass);
Mockito.when(executeClassSpy.getExternalData(Mockito.any()))
.thenReturn(mockData.getListOfString());
executeClassSpy.execute();
List<A> listOfA = mockData.getDesiredListOfA();
Mockito.verify(db2Dao).put(argumentCaptor.capture());
assertEquals(listOfA, argumentCaptor.getValue());
}
}

Unable to mock functions in when running mockmvc test

I am writting test case of my controller using mockmvc
#Mock
private AService aService;
#InjectMocks
private AController aController;
#BeforeEach
public void init() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders
.standaloneSetup(aController)
.setCustomArgumentResolvers(putAuthenticationPrincipal) // for passing the authentication principal
.build();
}
now when i trying to test
#Test
public void testfunction() throws Exception {
String id = UUID.randomUUID().toString();
Mockito.when(aService.getAccount(Mockito.anyString())).thenThrow(new Exception("not avalible"));
mockMvc.perform(MockMvcRequestBuilders.get("/account/{id}", id)
....
}
In this the aService.getAccount() is not getting mock. that is why I am not getting the desired result..
I didn't understand why the mocking of function isn't working in this case.
In a #WebMvcTest, you should not create a mock of your controller. Spring needs to create a controller in it’s context, and inject collaborating services into it.
To do that:
annotate the test class with #WebMvcTest(YourController.class)
annotate collaborating services with #MockBean, not #Mock

Mockito Issue with Long and Lombok

How to write mockito for the below code, I went through: https://examples.javacodegeeks.com/core-java/junit/junit-mockito-when-thenreturn-example/
Code:
#Override
public void saveEmployee(EmployeeDto dto) {
Department department = getByDepartmentId(dto.getDepartmentId());
RoleType roleType = getByRoleTypeId(dto.getRoleTypeId());
Employee departmentMember = convertToEntity(dto, department, roleType);
try {
departmentMemberRepository.save(departmentMember);
} catch (DataIntegrityViolationException e) {
throw new PCDataIntegrityViolationException("error");
} catch (Exception ex) {
throw new InternalServerException(HttpStatus.INTERNAL_SERVER_ERROR, "error", ex);
}
}
private Employee convertToEntity(EmployeeDto dto, Department department, RoleType roleType) {
return Employee.pmBuilder()
.memberEmployeeId(dto.getMemberEmployeeId())
.memberEmployeeName(dto.getMemberEmployeeName())
.createUser(dto.getCreateUser())
.lastUpdateUser(dto.getLastUpdateUser())
.status(StatusEnum.get(dto.getStatus()))
.department(department)
.roleType(roleType)
.build();
}
private Department getByDepartmentId(Long departmentId) {
Optional<Department> optDepartment = departmentRepository.findById(departmentId);
if(!optDepartment.isPresent()) {
throw new ResourceNotFoundException("Error");
}
return optDepartment.get();
}
private RoleType getByRoleTypeId(Integer roleTypeId) {
RoleType roleType = roleTypeRepository.findByRoleTypeId(roleTypeId);
if(roleType == null) {
throw new ResourceNotFoundException("error");
}
return roleType;
}
I've written test class, only issue is that
#RunWith(PowerMockRunner.class)
#PrepareForTest({AHUtils.class })
public class EmployeeServiceTest {
#InjectMocks
private EmployeeServiceimpl employeeServiceimpl;
#Mock
private Pageable pageable;
#Mock
private Page<Employee> employeePage;
#Mock
private EmployeeRepository employeeRepository;
#Mock
private DepartmentRepository departmentRepositoryMock;
#Mock
private Employee employee;
#Mock
private Optional<Employee> employeeOptional;
#Mock
private Department departmentMock;
#Mock
private Optional<Department> departmentOptionalMock;
#Mock
private EmployeeDto employeeDto;
#Mock
private Sort sortMock;
#Mock
private Exception ex;
#Mock
private Environment env;
#Test(expected = ResourceNotFoundException.class)
public void test_RoleTypeNotPresent() {
when(departmentOptionalMock.get()).thenReturn(departmentMock);
when(departmentOptionalMock.isPresent()).thenReturn(true);
when(departmentRepositoryMock.findById(null)).thenReturn(departmentOptionalMock);
doThrow(new ResourceNotFoundException("error")).when(employeeRepository).save(any());
when(employeeDto.getDepartmentId()).thenReturn(null);
employeeServiceimpl.saveEmployee(employeeDto);
}
}
when Optional<Department> optDepartment = departmentRepository.findById(departmentId);, I wanted to have value in that so that I will go ahead, this testcase going inside if block.
In case your DepartmentRepository does not get injected into your EmployeeServiceimpl make sure of the following things
(Based on the javadoc of InjectMocks):
In case you have at least one constructor with arguments:(Mockito used constructor injection in that case)All mocks that are supposed to be injected must be parameters of your constructor with the largest number of arguments.Also note that mockito won't consider the other injection methods if there is a non no-args consturctor.
Second case would be you have setter method for the things you want to mock
(Mockito will use setter injection in that case)
In case you only have a no-args constructor and no setters:
(Mockito will use field injection in that case)All mocks annotated with #Mock have to share the same name as the fields in your EmployeeServiceimpl class.
Overmocking generally refers to the fact you generate too much mocks, even for things that are not needed to be mocks.
You could change the first 3 lines to what the example belows shows.
Note that I changed the .findById(null) to .findById(anyLong()).
I am not sure what getDepartmentId() actually returns, for a primitive long you have to use anyLong() as a mock would return 0 (and not null) by default.
However in the example below I set the departmentId to 1L so it should match regardless.
#RunWith(PowerMockRunner.class)
#PrepareForTest({AHUtils.class })
public class EmployeeServiceTest {
#InjectMocks
private EmployeeServiceimpl employeeServiceimpl;
#Mock
private DepartmentRepository departmentRepositoryMock;
#Test(expected = ResourceNotFoundException.class)
public void test_RoleTypeNotPresent() {
Department department = new Department();
department.setDepartmentId(1L);
// only if you can't simply create that object, use the mock
// Department department = Mockito.mock(Department.class);
when(departmentRepositoryMock.findById(anyLong())).thenReturn(Optional.of(department));
// ... the rest of the example does not match with the code you posted ...
employeeServiceimpl.saveEmployee(employeeDto);
}
}
Note that the remaining part of your test,
doThrow(new ResourceNotFoundException("error")).when(employeeRepository).save(any());
when(employeeDto.getDepartmentId()).thenReturn(null);
does not really match to the code you posted.
Instead your should define some behaviour on the mock of roleTypeRepository.
I am also not sure at what point a exception should be thrown, as there does not seem to be any interaction with an employeeRepository.

How to Mock repository calls ATG

Can we use Mockito to write tests for methods which implements repository calls? For example below method is using Named query to get eBooks from a Book Repository -
public RepositoryItem[] getEBooks(DynamoHttpServletRequest request) {
RepositoryItem[] results = null;
Repository rep = (Repository) request.resolveName("/atg/products/BookRepository");
try {
RepositoryItemDescriptor desc = rep.getItemDescriptor("Book");
RepositoryView view = desc.getRepositoryView();
if (view instanceof NamedQueryView) {
NamedQueryView nameView = (NamedQueryView) view;
ParameterSupportView pSupportView = (ParameterSupportView) view;
String queryName = "GetBooks";
Query namedQuery = nameView.getNamedQuery(queryName);
Object[] params = { "ebook" }; //book type
results = pSupportView.executeQuery(namedQuery, params);
}
} catch (RepositoryException e) {
logError(e.getMessage());
}
return results;
}
Thanks.
Yes you can. The question is though are you testing YOUR code or ATG in this instance?
Assuming your method above is contained in a class called GetBooks your test could look something like this:
#InjectMocks private GetBooks testObj;
#Mock private DynamoHttpServletRequest requestMock;
#Mock private Repository bookRepositoryMock;
#Mock private RepositoryItemDescriptor bookRepositoryItemDescriptorMock;
#Mock private GSAView bookRepositoryViewMock; //The only oddity here but GSAView is the common denominator for NamedQueryView and ParameterSupportView
#Mock private Query namedQueryMock;
#Mock private RepositoryItem resultRepositoryItem1, resultRepositoryItem2;
#BeforeMethod(groups = { "unit" })
public void setup() throws Exception {
testObj = new GetBooks();
MockitoAnnotations.initMocks(this);
Mockito.when(requestMock.resolveName("/atg/products/BookRepository")).thenReturn(bookRepositoryMock);
Mockito.when(bookRepositoryMock.getItemDescriptor("Book")).thenReturn(bookRepositoryItemDescriptorMock);
Mockito.when(bookRepositoryItemDescriptorMock.getRepositoryView()).thenReturn(bookRepositoryViewMock);
Mockito.when(bookRepositoryViewMock.getNamedQuery("GetBooks")).thenReturn(namedQueryMock);
List<RepositoryItem> resultArrayList = new ArrayList<RepositoryItem>();
resultArrayList.add(resultRepositoryItem1);
resultArrayList.add(resultRepositoryItem2);
Object[] params = { "ebook" }; //It may be simpler to test if this was a constant
Mockito.when(bookRepositoryViewMock.executeQuery(namedQueryMock, params)).thenReturn(resultArrayList.toArray(new RepositoryItem[resultArrayList.size()]));
}
#Test(groups = { "unit" })
public void testGetEBooks()throws Exception{
RepositoryItem[] result = testObj.getEBooks(requestMock);
Assert.assertTrue(result.length == 2); //What do you want to test?
}
This gives a greenbar when executed via TestNG. But what are you really testing here?
On a separate note. You should really use (protected) constants more since you'll then be able to use them in the package scope of your Mockito tests.

Resources