Unit testing a method that calls a method on newly created instance? - spring-boot

We need to write junit test for below method.
public void Logout(){
new SecurityContextLogoutHandler.logout();
}
How can we test where securitycontextLogoutHandler.logout method is called?
We are able to verify that a new instance of securitycontextLogoutHandler is created by usinf PowerMockito but not able to verify logout method call.
Below is the Test written:
SecurityContextLogoutHandler securityContextLogoutHandler =
PowerMockito.mock(SecurityContextLogoutHandler.class);
PowerMockito.verifyNew(SecurityContextLogoutHandler.class);

Related

Trying to update embedded database when mocked http response is returned using Wiremock of MockServer

Working in a Spring Boot context, I am testing a service that queries a db, then makes a remote call that updates the db, then requeries the db to get the updated data.
I am trying to use Wiremock or MockServer to mock the remote call, but can't figure out how to update the embedded database as part of the mock server response generation process.
For example, using MockServer, I tried creating a callback class that had an autowired JdbcTemplate instance, but in the context of the callback that JdbcTemplate variable is null.
public class ApprovalHappyPathCallback implements ExpectationResponseCallback {
JdbcTemplate jdbcTemplate;
#Autowired
public void setDataSource(DataSource ds) {
jdbcTemplate = new JdbcTemplate(ds);
}
public static final HttpResponse httpResponse = response()
.withStatusCode(HttpStatusCode.ACCEPTED_202.code())
.withHeaders(
header("x-callback", "test_callback_header"),
header("Content-Length", "a_callback_response".getBytes(UTF_8).length),
header("Connection", "keep-alive")
)
.withBody("a_callback_response");
#Override
public HttpResponse handle(HttpRequest httpRequest) {
if (httpRequest.getMethod().equals("GET")) {
jdbcTemplate.execute("update communications set status = 'APPROVED_SCHEDULED' where id = 153511");
return httpResponse;
} else {
return notFoundResponse();
}
}
}
The call back executes, but the jdbcTemplate statement does not work.
The callback is referenced like this in the test:
mockServer.when(request().withMethod("GET"))
.withBody("Approved")
// );
.respond(
callback()
.withCallbackClass(ApprovalHappyPathCallback.class)
);
The service method that makes the remote call is essentially:
public CommunicationEntity approveCommunication(Long communicationId) {
String approvalToken = commRepo.approvalTokenById(communicationId);
if (approvalToken == null) {
approvalToken = UUID.randomUUID().toString();
communicationEntity.setApprovalToken(approvalToken);
commRepo.save(communicationEntity);
}
String approvalResponse = remoteCommunicationApprover.approveCommunication(communicationId, approvalToken);
CommunicationEntity communicationEntity = getCommunicationById(communicationId);
if (communicationEntity.getStatus() != CommunicationStatus.Approved_Scheduled) {
throw new BadRequestException(
"Approval request for communication " + communicationId + " and token " + approvalToken
+ " failed with remote response: " + approvalResponse,
ErrorCodes.COMMUNICATION_SVC_REMOTE_APPROVAL_REQUEST_FAILED);
}
return communicationEntity;
There were two issues causing problems: making sure the jdbcTemplate used in the callback method was configured with the correct DataSource, and making sure that the data in the embedded in memory DB was accessible from the MockServer response generation thread.
I solved the first problem by using a lambda or closure for the MockServer callback in which I use the JdbcTemplate instance created in the test class with the autowired DataSource (though solutions exist for the callback class approach as well).
The second problem was the result of the fact that the test method was within a transaction and so inserts to the DB made at the beginning of the test were not committed when the MockServer thread (note that the MockServer response generation happens in a different thread than the main thread where the test method is running) was executing the callback. Thus those inserts were not accessible to the callback.
The solution was to annotate the test method with #Transactional(propagation = Propagation.NOT_SUPPORTED)
See h2 database access to test data from separate threads

Mockito MockedStatic when() "Cannot resolve method"

I am trying to use Mockito MockedStatic to mock a static method.
I am using mockito-core and mockito-inline version 3.6.0 with Spring Boot and maven.
I can't manage to make the mock work, I have a "Cannot resolve method post" on the Unirest::post that you can see in the code below:
#Test
public void test() {
try (MockedStatic<Unirest> mock = Mockito.mockStatic(Unirest.class)) {
mock.when(Unirest::post).thenReturn(new HttpRequestWithBody(HttpMethod.POST, "url"));
}
}
The Unirest class comes from the unirest-java package.
Did someone encounter this issue already and have a solution?
The method Unirest.post(String url) takes an argument and hence you can't refer to it using Unirest::post.
You can use the following:
#Test
void testRequest() {
try (MockedStatic<Unirest> mockedStatic = Mockito.mockStatic(Unirest.class)) {
mockedStatic.when(() -> Unirest.post(ArgumentMatchers.anyString())).thenReturn(...);
someService.doRequest();
}
}
But keep in mind that you have to mock now the whole Unirest usage and every method call on it as the mock returns null by default.
If you want to test your HTTP clients take a look at WireMock or the MockWebServer from OkHttp. This way you test your clients with real HTTP communication and can test also corner cases like slow responses or 5xx HTTP codes.

Can we mock "CordaRPCops" in Cordapp for testing purpose?

Is it possible to mock CordaRPCops so as to execute a flow in project without creating a standalone node or in-memory node (like in a mock network) ? Kindly let me know.
I am also adding a link which I found informative regarding this from github issues QA
There is no specific class available mock CordaRPCops in the TestDSL. If you referring to mock some of the fuctionality of the node for cordapp testing, you should use the MockNode.
If you want to Mock CordaRPCops in the client app, you could use mockito to do so, example below:
Test:
#Test
public void testGetStateList(){
CordaRPCOps cordaRPCOps = Mockito.mock(CordaRPCOps.class);
Service service = new Service(cordaRPCOps);
Vault.Page<MyState> myStatePage =
new Vault.Page<>(Collections.EMPTY_LIST, Collections.EMPTY_LIST, 0L, Vault.StateStatus.ALL, Collections.EMPTY_LIST);
Mockito.when(cordaRPCOps.vaultQuery(MyState.class)).thenReturn(myStatePage);
service.getStateList();
}
Service:
public class Service {
CordaRPCOps cordaRPCOps;
public Service(CordaRPCOps cordaRPCOps) {
this.cordaRPCOps = cordaRPCOps;
}
public List<StateAndRef<MyState>> getStateList() {
return cordaRPCOps.vaultQuery(MyState.class).getStates();
}
}

Test Observable.FlatMap Mockito

I've been looking on internet but haven't found the solution if any (new on UnitTest and Mockito)
It's possible to test a method that return a call of a service and manipulate it's result before to return it? Example;
public Observable<Reports> getUserReports(Integer userId) {
return serviceClient
.getReports(userId)
.flatMap(serviceReports -> {
System.out.println("Testing inside flatMap"); <- never reach this line therefore duno if methods down here are invoked and work perfectly
final Observable<List<Report>> reports = getPendingReports(userId, serviceReports);
//More methods that modify/update information
return zip(observable1, observable2, observable3
(report1, report2, report3) -> {
updateReports(otherArguments, report1, report2, report3);
return serviceReports;
});
});
}
So far I've tried;
#Test
public void myTest(){
when(serviceClient
.getReports(anyInt()))
.thenReturn(Observable.just(reports));
Observable<Reports> result = mocketClass.getUserReports(userId)
}
Tryed with Spy and Mock but no luck so far. Any hint or help would be great.
To mock getReports() behavior you need to mock the serviceClient firstly and pass it into your service class.
Just as example:
#Test
public void myTest(){
// Given
final ServiceClient mockedServiceClient = Mockito.mock(ServiceClient.class);
when(mockedServiceClient
.getReports(anyInt()))
.thenReturn(Observable.just(reports));
// and create an instance of your class under testing with injected mocked service client.
final MyUserService userService = new MyUserService();
userService.setServiceClient(mockedServiceClient);
// When run a method under test
Observable<Reports> actualResult = userService.getUserReports(userId)
// Then
// actualResult to be verified.
}

Access instance of class in TestNG run in groovy

I have a spring-based groovy application that is used as a "framework" for running TestNG tests.
Here is a part of my application
#RestController
class Framework{
def instance
#RequestMapping("/test/{name}")
#ResponseBody
String home(#PathVariable String name) {
def sourceFile = new File("./tests/${name}/test.groovy")
groovyClass = new GroovyClassLoader(getClass().getClassLoader()).parseClass(sourceFile)
instance = groovyClass.newInstance()
def testNG = new TestNG()
testNG.setOutputDirectory("./results/${name}")
XmlSuite suite = new XmlSuite()
suite.setName(name)
XmlTest test = new XmlTest(suite)
test.setXmlClasses([new XmlClass(groovyClass)])
testNG.setXmlSuites([suite])
testNG.run()
def resultFile = new File("./results/${name}/emailable-report.html")
return resultFile.text
}
#RequestMapping("/status")
public String getStatus(){
return instance.currentMethod
}
}
My example test file looks like
class T1{
public String currentMethod
#Test
public void test() {
//execution
}
#Test
public void test2(){
//execution
throw new Exception()
}
}
It works fine as it is but I wanted to implement some additional information to be able to check which method is currently running by adding some more code
#BeforeMethod
void setMethodName(){
String className = this.class.getName()
def classData = Thread.currentThread().getStackTrace().toList().reverse().find{ it =~ /${className}/}
currentMethod = classData.getMethodName()
}
However I am not able to access the instance as
instance = groovyClass.newInstance()
creates one instance and
testNG.run()
creates another which can be confirmed by printing some mesages in construcor.
ctor
ctor
[TestNG] Running:
Command line suite
===============================================
Total tests run: 2, Failures: 1, Skips: 0
===============================================
Any idea how can I access istance created by TestNG or how to pass existing instance into TestNG runner?
Each time i try to access localhost:8080/status it returns null.
ITestListener is what you are looking for. Check its documentation.
You'll be able to add the listener with:
testNG.addListener(....);
And we can imagine your listener will have:
listener.getCurrentMethod();
And fyi, it is possible to inject a Method instance into a #BeforeMethod method.

Resources