Unit Test class that uses only local variables for composition - java

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;
}};
}
}

Related

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

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.

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.

How to write unit tests for this simple application

I have an application with a class registered as a message listener that receives messages from a queue, checks it's of the correct class type (in public void onMessage(Message message)) and sends it to another class that converts this class to a string and writes the line to a log file (in public void handleMessage(MessageType m)). How would you write unit tests for this?
If you can use Mockito in combination with JUnit your test could look like this:
public void onMessage_Success() throws Excepton {
// Arrange
Message message = aMessage().withContent("...").create();
File mockLogFile = mock(File.class);
MessageHandler mockMessageHandler = mock(MessageHandler.class);
when(mockMessageHandler).handleMessage(any(MessageType.class)
.thenReturn("somePredefinedTestOutput");
when(mockMessageHandler).getLogFile().thenReturn(mockLogFile);
MessageListener sut = spy(new MessageListener());
Whitebox.setInternalState(sut, "messageHanlder", mockMessageHandler);
// or simply sut.setMessageHandler(mockMessageHandler); if a setter exists
// Act
sut.onMessage(message);
// Assert
assertThat(mockLogFile, contains("your desired content"));
verify(sut, times(1)).handleMessage(any(Message.class));
}
Note that this is just a simple example how you could test this. There are probably plenty of other ways to test the functionality. The example above showcaeses a typical builder-pattern for the generation of default-messages which accept certain values for testing. Moreover, I have not really clarified the Hamcrest matcher for the contains method on the mockLogFile.
As #Keppil also mentioned in his comment, it makes sense to create multiple test-cases which varry slightly in the arrange and assert parts where the bad-cases are tested
What I probably didn't explain enough is that getLogFile() method (which with high certainty has an other name in your application) of MessageHandler should return the reference to the file used by your MessageHandler instance to store the actual log-messages. Therefore, it probably is better to define this mockMessageHandler as spy(new MessageHandler()) instead of mock(MessageHandler.class) although this means that the unit-test is actually an integration test as the interaction of two classes is tested at the same time.
But overall, I hope you got the idea - use mock(Class) to generate default implementations for dependencies your system-under-test (SUT) requires or spy(Instance) if you want to include a real-world object instead of one that only has null-values as return types. You can take influence on the return-value of mocked objects with when(...).thenReturn(...)/.thenThrow(...) or doReturn(...).when(...) in case of void-operations f.e.
If you have dependency-injection into private fields in place you should use Whitebox.setInternalState(...) to inject the values into the sut or mock classes if no public or package-private (if you obtain the testing-model of reusing the package structure of the system-under-test classes within your test-classes) setter-methods are available.
Further, verify(...) lets you verify that a certain method was invoked while executing the SUT. This is quite handy in this scenario when the actual assertion isn't that trivial.

I can't unit test my class without exposing private fields -- is there something wrong with my design?

I have written some code which I thought was quite well-designed, but then I started writing unit tests for it and stopped being so sure.
It turned out that in order to write some reasonable unit tests, I need to change some of my variables access modifiers from private to default, i.e. expose them (only within a package, but still...).
Here is some rough overview of my code in question. There is supposed to be some sort of address validation framework, that enables address validation by different means, e.g. validate them by some external webservice or by data in DB, or by any other source. So I have a notion of Module, which is just this: a separate way to validate addresses. I have an interface:
interface Module {
public void init(InitParams params);
public ValidationResponse validate(Address address);
}
There is some sort of factory, that based on a request or session state chooses a proper module:
class ModuleFactory {
Module selectModule(HttpRequest request) {
Module module = chooseModule(request);// analyze request and choose a module
module.init(createInitParams(request)); // init module
return module;
}
}
And then, I have written a Module that uses some external webservice for validation, and implemented it like that:
WebServiceModule {
private WebServiceFacade webservice;
public void init(InitParams params) {
webservice = new WebServiceFacade(createParamsForFacade(params));
}
public ValidationResponse validate(Address address) {
WebService wsResponse = webservice.validate(address);
ValidationResponse reponse = proccessWsResponse(wsResponse);
return response;
}
}
So basically I have this WebServiceFacade which is a wrapper over external web service, and my module calls this facade, processes its response and returns some framework-standard response.
I want to test if WebServiceModule processes reponses from external web service correctly. Obviously, I can't call real web service in unit tests, so I'm mocking it. But then again, in order for the module to use my mocked web service, the field webservice must be accessible from the outside. It breaks my design and I wonder if there is anything I could do about it. Obviously, the facade cannot be passed in init parameters, because ModuleFactory does not and should not know that it is needed.
I have read that dependency injection might be the answer to such problems, but I can't see how? I have not used any DI frameworks before, like Guice, so I don't know if it could be easily used in this situation. But maybe it could?
Or maybe I should just change my design?
Or screw it and make this unfortunate field package private (but leaving a sad comment like // default visibility to allow testing (oh well...) doesn't feel right)?
Bah! While I was writing this, it occurred to me, that I could create a WebServiceProcessor which takes a WebServiceFacade as a constructor argument and then test just the WebServiceProcessor. This would be one of the solutions to my problem. What do you think about it? I have one problem with that, because then my WebServiceModule would be sort of useless, just delegating all its work to another components, I would say: one layer of abstraction too far.
Yes, your design is wrong. You should do dependency injection instead of new ... inside your class (which is also called "hardcoded dependency"). Inability to easily write a test is a perfect indicator of a wrong design (read about "Listen to your tests" paradigm in Growing Object-Oriented Software Guided by Tests).
BTW, using reflection or dependency breaking framework like PowerMock is a very bad practice in this case and should be your last resort.
I agree with what yegor256 said and would like to suggest that the reason why you ended up in this situation is that you have assigned multiple responsibilities to your modules: creation and validation. This goes against the Single responsibility principle and effectively limits your ability to test creation separately from validation.
Consider constraining the responsibility of your "modules" to creation alone. When they only have this responsibility, the naming can be improved as well:
interface ValidatorFactory {
public Validator createValidator(InitParams params);
}
The validation interface becomes separate:
interface Validator {
public ValidationResponse validate(Address address);
}
You can then start by implementing the factory:
class WebServiceValidatorFactory implements ValidatorFactory {
public Validator createValidator(InitParams params) {
return new WebServiceValidator(new ProdWebServiceFacade(createParamsForFacade(params)));
}
}
This factory code becomes hard to unit-test, since it is explicitly referencing prod code, so keep this impl very concise. Put any logic (like createParamsForFacade) on the side, so that you can test it separately.
The web service validator itself only gets the responsibility of validation, and takes in the façade as a dependency, following the Inversion of Control (IoC) principle:
class WebServiceValidator implements Validator {
private final WebServiceFacade facade;
public WebServiceValidator(WebServiceFacade facade) {
this.facade = facade;
}
public ValidationResponse validate(Address address) {
WebService wsResponse = webservice.validate(address);
ValidationResponse reponse = proccessWsResponse(wsResponse);
return response;
}
}
Since WebServiceValidator is not controlling the creation of its dependencies anymore, testing becomes a breeze:
#Test
public void aTest() {
WebServiceValidator validator = new WebServiceValidator(new MockWebServiceFacade());
...
}
This way you have effectively inverted the control of the creation of the dependencies: Inversion of Control (IoC)!
Oh, and by the way, write your tests first. This way you will naturally gravitate towards a testable solution, which is usually also the best design. I think that this is due to the fact that testing requires modularity, and modularity is coincidentally the hallmark of good design.

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