Mock a java web service Rest who invoke a static extern methode - java

I want to make an unit test of a web service (Rest- jersey) this is how my web service look likes
public class WebService {
public string webServiceMethode {
...
String a = ExternalClass.staticMethode("aa");
..
return b
}
}
as you can see the web service methode invoke a static methode in a external class, in test class my idea is to call the web service by Rest-Assured and mock the statics methode by Powermock and here my test methode logic
public class WebServicetest {
#Test
public void testWebServiceMethode {
mockStatic(ExternalClass.class);
when(ExternalClass.staticMethode(Mockito.any()))
.thenReturn("ok");
given().accept(CotentType.JSON)
.body(MyObject).when().post(new URI("/test"));
}
}
the given() methode will call the web service and the when().theReturn() will replace the return of the external static methode so the call works good but not the mock.
Thank you in advance for your help

A) Understand that static is an abnormality within good OOP. It kills polymorphism, and it leads to super tight coupling between your classes. The sane thing to do: avoid using static this way.
static can be OK, but as soon as it hampers your ability to do (easy) unit-testing, you are doing something wrong.
So, my first answer is: get rid of that static method.
B) In case you want to continue doing the wrong thing (using PowerMock) - simply read the tutorials or the documentation. There are various requirements in order make static mocking work. You need to use the #Runner(PowerMockRunner), and you need to use the #PrepareForTest annotation (for the class on which you want to mock static classes). So that PowerMock can go in and manipulate the byte code of your production code so it can do its magic.

Related

Unit Test class that uses only local variables for composition

I am writing app that uses various REST api endpoints with very similar properties. Only difference is in endpoint adress and payload. Headers, method and other stuff remain the same. That is why I created class to communicate with my remote host, it is called RestApiCommunicator that has method generateRequestAndCallEndpoint(List payload) that wraps payload with all required stuff needed to perform rest call.
Than, I have various classes that only call this communicator class with proper endpoint suffix an its resources.
Everything is working fine but I want to unit test all of those classes. I was trying to figure out how to do that by reading a lot of SO questions but they are rather complicated cases, my is very simple.
I am trying to figure out a proper way to unit test a class that looks like this one:
class MyRestClient {
public void useRestApi(List<MyResources> myResources) {
RestApiCommunicator restApiCommunicator = new RestApiCommunicator ("/some/endpoint");
restApiCommunicator.generateRequestAndCallEndpoint(myResources);
}
}
I want to test if communicator was created with proper enpoint adress and if generateRequestAndCallEndpoint was called exacly once with my sample payload.
Only thing that comes to my mind is that make restApiCommunicator a field, create setter for this field and mock it in Unit tests. But this seems to me as rather dirty solution and I wouldn't like to modify my code to allow tests.
Maybe you can point me in some direction where I could have this class tested using some good pattern.
(ps. If that matters - this is a Spring Boot app)
You could provide a factory for the communicator
class MyRestClient {
private RestApiCommunicatorFactory factory = ...
public void useRestApi(List<MyResources> myResources) {
factory.getCommunicator("/some/endpoint")
.generateRequestAndCallEndpoint(myResources);
}
In your unit test, you provide a mock of the factory, which returns mock communicators. The specific language for that depends on your mocking library of choice.
One way to do exactly what you ask (ie, "to test if communicator was created with proper enpoint adress and if generateRequestAndCallEndpoint was called exactly once with my sample payload") is to mock it using JMockit:
public final class MyRestClientTest {
#Tested MyRestClient restClient;
#Mocked RestApiCommunicator restApi;
#Test
public void verifyUseOfRestApi() {
List<MyResource> resources = asList(new MyResource("a"), new MyResource("b"));
restClient.useRestApi(resources);
new Verifications() {{
new RestApiCommunicator("/some/endpoint");
restApi.generateRequestAndCallEndpoint(resources); times = 1;
}};
}
}

How to properly write JUnit tests?

I'm a bit confused on how to properly write unit tests for my application.
Actually i want to know if i have to rewrite an existed method and modify it for junit or just call my existed method and use assert.
So far, i use the second option, but i've came across with a problem.
For example, inside a Controller method i'm getting the currently logged in user and pass it to some services. If i call this method through JUnit it will show null exception because there is no logged in user.
So,
1) do i have to rewrite these kind of methods for testing purposes?
2) Is it proper to call existed methods and use assertion anyway?
Thanks
#RequestMapping(value="/like", method=RequestMethod.GET)
public String msgLike(#RequestParam("msgId") long messageId, #RequestParam("like") boolean like){
User user = new User();
user = this.userService.getUserByName(this.userService.getLoggedInUsername()); //NULL EXCEPTION HERE WHEN TESTING
if(!messageService.checkIfLiked(user, messageId)){
if(like){
messageService.insertLike(messageId);
messageService.insertMessageUserLike(user, messageId);
}
if(!like){
messageService.insertDislike(messageId);
messageService.insertMessageUserLike(user, messageId);
}
}
return "redirect:/home";
}
Actually i want to know if i have to rewrite an existed method and modify it for junit or just call my existed method and use assert.
Just call your exiting method, In fact junit is written before writing logic for calling method.
Example:
If you want to test int square(int num) method, which find square of given num,
So write Junits like this ,
#Test
squareTest() {
int square = objectName.square(3);
assertThat(square , is(equalTo(9)));
}
And when coding done like this,
int square(int a) {
result=a*a;
return result;
}
Run your Junit.
For your second question,
You will have to read Mocking.
In your case you are trying to test a rest controller which is slightly different when testing normal methods. For example the following method:
public MyClass{
public static int sum(int a, int b){
return a + b;
}
}
Could simply be tested by:
#Test
public void testSum(){
assertEquals(3, MyClass.sum(1, 2));
}
But in your case you require the controller api to be used properly. i.e. you require a logged in user. For this you would need to test your controllers by accessing them as users would. This provides some explanation on the process and this answer provides even more details.
Essentially what you are looking for is unit testing rest controllers.
What you need to do is in testing, supply a fake userService that will give the function a User with properties relevant for that test.
Before the test, you need to set this.userService to your FakeUserService.
It's hard to be more specific without seeing more of your code.
This is a good question because this is a common problem when learning to write unit tests. Solving this problem will help you write better code.

Junit testing method which returns nothing and has service call to other system

I have a method which does following.
public void callService(SomeObject someObject) {
// call helper class method and create a request XML
// scrub this XML using a local method and persist it in MongoDB
// call a 3rd party service using HTTP POST
// Recieve the response
// Persist the response in MongoDB and set in in somObject
// return
}
Now as part of development we have to write unit test cases for this method. I am new to Junit testing as well as mock objects. but when I googled and looked at the some other similar questions I understood that testing void method is little bit different than normal methods and I think my above method which special in some more way as I am clueless as to what and how to test for this method.
Can someone please give me pointer or any reference as to how I can unit test this method using Junit.
You'd probably want to use mocks to stand in for your Mongo connection and the third party service. It's easiest to use an existing mock framework, but this is the general concept.
Pretend that you post to this third party service by constructing a StuffToPost object and passing it to the post method on your ThirdPartyPoster. Then you can create a mock object as follows:
public class MockThirdPartyPoster implements ThirdPartyPoster {
private int count = 0;
private StuffToPost stuffToPost;
#Override
public void post(StuffToPost stuffToPost) {
this.count++;
this.stuffToPost = stuffToPost;
}
public int getCount() {
return count;
}
public StuffToPost getStuffToPost() {
return stuffToPost;
}
}
In your test, you'd construct this MockThirdPartyPoster and pass it to thingToTest.setThirdPartyPoster, then call your method. Once the method finishes executing, you can call getCount() on the mock to make sure that you POSTed once and only once, and call getStuffToPost() to examine the StuffToPost object and make sure that it is correct. You'd do something similar for Mongo persistence as well.
That calls for a lot of boilerplate; mock frameworks like Mockito or EasyMock exist to solve that problem.

Clarification in Java Code Testing

I have started reading the Spring in Action book.
I have no knowledge of JUnit which I think my doubt is about.
There is a code fragment where the author refers to and says that it is difficult to test:
package com.springinaction.knights;
public classDamselRescuingKnight implements Knight {
private RescueDamselQuest quest;
public DamselRescuingKnight() {
quest = new RescueDamselQuest();
}
public voidembarkOnQuest() throwsQuestException {
quest.embark();
}
}
The author says that:
It’d be terribly difficult to write a unit test for DamselRescuingKnight. In such a test, you’d like to be able to assert that the quest’s embark() method is called when the knight’s embarkOnQuest() is called. But there’s no clear way to accomplish that here. Unfortunately, DamselRescuingKnight will remain untested.
What does the author mean by this?
Why is the code difficult to test here?
My initial thought is that it is difficult to test because the "RescureDamselQuest" object is initialized in the constructor. This makes it difficult to for example insert a mock object. A mock object would help you test that the embark() method is called on the "RescueDamselQuest" object.
A better way to solve this can be to either include a parameter in the constructor (usually I prefer this method):
public DamselRescuingKnight(RescueDamselQuest quest){
this.quest = quest;
}
Or add a setter:
public void setDamselRescuingKnight(RescueDamselQuest quest){
this.quest = quest;
}
A common example I give is consider that you want to open a file, parse it, and get a data class out. Most will do something like:
Data openAndParse(String filename) {
...openFile
...parse
}
By doing it this way, the file open methodology and parse is highly coupled and difficult to test. If you have a problem in open and parse is it with the parse or the open?
By writing JUnit test, you are forced, for simplicity sake, to do something like...
BufferedReader openFile(String filename) {
...open file and return reader
}
Data parse(BufferedReader input) {
...parse and return data
}
JUnit leads us to a more cohesive solution. We write JUnit test simply by creating a string, constructing a StringReader, and then a BufferedReader. Well guess what? Very similarly we can now use parse to accept input from a variety of sources not just the file.
It's difficult to test because the quest implementation cannot be swapped out. Without byte code modification there's no trivial way to see if embark is called.
If you could set the quest implementation in a constructor or setter you could pass in an implementation that can spy on the call to embark.
One need to increase accessibility of fields and method of class to test. For example if one is testing a method which is package-private (default) then test cases which are generally in different package will not able to test this method. Therefore it is advised to to change in accessibility of fields to test the method. DamselRescuingKnight class can be tested which is not using DI by modifying the accessibility of RescueDamselQuest field from private to default. Then writing test case using mockito. Here is code for test case
#Test
public void knightShouldEmbarkOnQuest() throws QuestException {
DamselRescuingKnight knight = new DamselRescuingKnight();
RescueDamselQuest quest = mock(RescueDamselQuest.class);
knight.quest = quest;
knight.embarkOnQuest();
verify(quest, times(1)).embark();
}
And line which was changed in DamselRescuingKnight class to remove private accessibility
RescueDamselQuest quest;

How to design a private/final method available for mocking?

This is the class that I have to test:
public class Downloader {
public String download(String uri) {
HttpClient client = this.getHttpClient();
client.setURI(uri);
return client.get();
}
private HttpClient getHttpClient() {
HttpClient client = new HttpClient();
// + some config
return client;
}
}
Very simple. Now I want to test its behavior when getHttpClient() throws an exception. However, I can't mock this method, since it is private. What is a common practice in such a situation?
I would make the HTTPClient a field of the class that is set up on construction (via a interface). Then you have the ability to create a mock HTTPClient that can throw an exception during the test if you want, e.g.:
public class Downloader {
private IHTTPClient client;
public Downloader(IHTTPClient client) {
this.client = client;
}
public String download(String uri) {
this.initialiseHttpClient();
client.setURI(uri);
return client.get();
}
private HttpClient initialiseHttpClient() {
// + some config
}
}
Then call the constructor with a real HTTPClient in production code and a Mock in the test code. You may need to create a wrapper for HTTPClient for the real code.
If you're trying to test private methods, I think something's not quite right.
You should be testing your class against its contract. The private methods are implementation-dependent, and so (in a sense) it doesn't matter what they do. You should be checking that your public methods work as expected in both functioning and non-functioning scenarios, and reflect this as appropriate back to the client (in this case, your test class).
You may need to substitute some functionality into your class for test purposes (e.g. substitute in a broken JDBC connection etc.) In that scenario I would investigate mocking and dependency injection.
It does sound a little cheesy but I generally make methods like this public and add conspicuous javadocs saying "this method is exposed public only for testing".
You can also use package-only access by having the xunit/mock etc. in the same package.
I tend to prefer using simple solutions like this as opposed to more complex and hard-to-debug techniques like AOP-style code injection.
You could make getHttpClient() protected and subclass it in the test to return what you want, so you'd have something like this in your tests:
public class TestableDownloader extends Downloader {
protected HttpClient getHttpClient() {
throw new Exception();
}
}
This isn't ideal though, you'd be better having a different design which didn't require you to test private methods (perhaps using dependency injection to provide a factory or something).
Private methods are not supposed to get a unit test. You are only supposed to unit test public methods. How a public method is organized internally does not matter to unit testing. A unit is not equal to a method. It is equal to a behavior that is possibly using more than one method to do its job.
Mocking is also a useless thing to do. If you have to mock something, your method is really integrating functions. Your code is needing refactoring to make it only do one thing and then a wrapper method calls it and the to be mocked object to integrate it.
Unit testing is something that sounds like you should do but in reality is a waste of effort that you are better to use in coding your application. Unit testing is no guarantee of better code quality and maybe it is making it worse because you are not spending enough time on your real code.

Categories

Resources