Mock an object which is not injected - java

I'm new to Java programming and I have the following code:
import javax.ws.rs.client.ClientBuilder;
public class Foo {
private final Client http;
Foo() {
http = ClientBuilder.newClient().register(CurlRequestFactory.getCurlRequestFactory().get(LOGGER, “someString”));
}
public someMethod() {
Invocation.Builder request = http.target(getURI(“someUri”)).request().header(“someHeader”, “someValue”);
Response response = request.get();
}
}
I want to write a unit test for someMethod() where request.get() would throw an exception. For this I require that request object should be set as a mock object.
But I'm unable to do so as it is being initialized directly instead of getting injected.
I know I can mock an object if it was getting injected as below:
Response responseMock = Mockito.mock(Response.class);
Mockito.when(responseMock.get()).thenThrow(new Exception("someMessage"));
But I couldn't find anything which works for my scenario.
PS: I don't want to use Powermock.

I have come across few things that Mokito does not support. One is this scenario. Either you have to change your code to inject it or use PowerMockito. I don't think there is any other option.

Your method is probably doing too many things. I imagine that you don't want to just return the Response from someMethod. Refactor your code to someMethod(Response response) or even better someMethod(Pojo responseBody) and then test that.
I don't know what your use case is, but someMethod probably belongs to another class (I'll call it Bar) separate from the http client class (Foo). You can then inject Foo into Bar and do the test. Is there any reason why you wouldn't want to refactor to that?

Related

Intercepting an assignment in Java

I'm using REST-Assured library with TestNG for receiving the response in a Response object as below.
Response response;
#Test
public void someTest() {
RestAssured.baseURI = "some_valid_baseURI";
RestAssured.basePath = "some_valid_endpoint";
response = RestAssured.given().contentType(ContentType.JSON).when().get();
}
I have several test methods like the above-mentioned method in a test class. Is there any way to intercept the response assignment so that I can, somewhere else (e.g. in a method annotated by an #AfterMethod), know that the method being used to get the response is the GET method?
PS: I did not find any in-built way in the REST-Assured library to do this.
The answer in Is it possible to extract the method name from the response object? serves my purpose for this question. Sorry about the generic question line here though!

Play route/Controller just for unit test

I have a method that takes a Play Http.Context and "does some stuff" with the session. I want to write a unit test for just that method. Specifically, I want to test that if a request comes in with certain headers my method works correctly. It seems like the easiest way to do that reliably is to create a FakeApplication and a Controller for my test. Then I'd use Helpers.fakeRequest to get a request and Helpers.route to route that request to my controller. The controller would call my method, set some variables, etc. and I could then assert success and such.
Seems like a splendid plan but I can't figure out how to add a route to my controller in the FakeApplication. Note that this controller isn't really part of my app - it's just something I want to use for this one test. So I want to define it and construct in just this one unit test; I don't want to add it to my conf/routes file.
Specifically, I want something like this:
// Maybe I can use GlobalSettings.onRouteRequest but the return type
// is play.api.mvc.Handler which seems inaccessible from Java
FakeApplication app = Helpers.fakeApplication(new MyGlobalSettings());
Http.Request request = Helpers.fakeRequest().withCookies(...).withBody(...);
Controller testContoller = new MyTestController();
// This doesn't exist, but I want something like this
app.addRoute("/foo", ctx -> testController.method(ctx));
running(app, () -> {
Helpers.route("/foo");
assertThat(testContoller.itWorked()).isTrue();
}
I'm running Play 2.2.3 and writing in Java, not Scala.
I do realize I can construct an Http.Context directly and pass that to my method. However, this isn't my preferred approach for a few reasons:
The Http.Context constructor takes the plain text of the session variables. I want to test that things work correctly when the request contains the encrypted session cookie.
The Http.Context constructor is poorly documented and seems a bit off. For example, you can pass an Http.Request to the constructor, but you also pass the cookie data and session data. So what happens to the cookie/session data on the request? Does it get merged with the other data passed? Ignored?
The Http.Context constructor is difficult to use from Java as it requires a play.api.mvc.RequestHeader, which can't be constructed in Java, and a play.mvc.Http.Request which can't be "usefully" constructed from Java (you can construct one, but without cookies, headers, etc. and FakeRequest can't be converted to an Http.Request).
It feels more "black box" to send in a request and ensure things work rather than try to figure out how this particular version of Play converts my request it an Http.Context (e.g manually constructing a context seems more likely to break with new versions of play).
Any ideas?
Play Tests in format
running(fakeApplication(), () -> {
...
});
Are good for testing a running play app without the HTTP layer. However in your case you're dependent on having a http context so I your options are to either add in the http layer...
running(testServer(3333), fakeApplication(), () -> {
WSResponse wsResponse = WS.url("http://localhost:3333/foo").setHeader("fizz", "buzz").get().get(30, TimeUnit.SECONDS);
....
//assert some stuff
});
or maybe try using PowerMockito and mock out the HTTP.Context call. As you point out this is more brittle but will allow to pragmatically spin up a quick unit test. Something like
#RunWith(PowerMockRunner.class)
public class FooTest {
#PrepareForTest({ Http.Context.class })
#Test
public void test() {
mockStatic(Http.Context.class)
mockStatic(Http.class)
Http.Context mockContext = mock(Http.Context.class);
Map<String, String> args new HashMap<>();
args.put("a","b");
mockContext.args = args;
PowerMockito.when(Http.Context.current()).thenReturn(mockContext);
ClassUnderTest cut = new ClassUnderTest();
cut.someMethod();
//assertions
}
}
#Before
public void startPlay() {
String conf = System.getProperty("config.file");
if (conf == null) {
System.setProperty("config.file", "../../conf/test.conf");
}
System.setProperty("play.http.router", "customer.Routes");
super.startPlay();
}
This is how you add an additional test route without changing your conf/routes file. But MyTestController.java needs to be located at project/app instead of project/test.
// app/controllers/TestController.java
public static Result foo() {
return ok();
}
// conf/test.routes
GET /foo controllers.TestController.foo
// test/controllers/TestTestController.java
#Before
Configuration config = new Configuration(ConfigFactory.parseFile(new File("conf/test.conf")).resolve());
Map<String, Object> configMap = config.asMap();
Map<String, Object> application = (Map<String, Object>) config.get("application");
application.put("router", "test.Routes");
configMap.put("application", application);
fakeApplication(configMap);
#Test
FakeRequest fakeRequest = Helpers.fakeRequest("GET", "/foo");
Result result = Helpers.route(fakeRequest);
assertThat(Helpers.status(result)).isEqualTo(200);

Test Method Called Without Having Argument In Test Class

I have a class which takes a message with payload String.
The payload is then split and used to create an Entity which is passed to DAOInterface to persist.
How can you test the call daoInterface.insert(entity) has been made?
To Mock the DAOInterface and then verify the call to DAO requires the entity in the test class i.e.
verify(daoInterface).insert(entity);
Is this bad design i.e. creating the entity at this stage? Should the Sting[] split be passed to the DAOImplementaion and initialized there. Example problem,
public class ServiceClass {
#AutoWire
private DAOInterface daoInterface;
public void serviceMessage(Message<String> message) {
MessageHeaders mh = new MessageHeaders(message.getHeaders());
String[] split = ((String) mh.get("payload")).split("_");
code omitted
...
String type = mh.get("WhatType");
Entity entity = new Entity(split[0], split[1], split[2]);
if (type.equals("one"))
{
daoInterface.insert(entity); //How to test?
}
else
{
if (type.equals("two"))
{
doaInterface.modify(entity); //How to test?
}
}
}
}
You can verify with Mockito Matchers.
If you only care that the method is called with some Entity, you can verify that with
verify(daoInterface).insert(any(Entity.class));
If you care about which Entity, and the Entity class has an equals method, you can make an entity that should be equal to the one created and verify with
verify(daoInterface).insert(eq(expectedEntity);
If it's more complex than either of these cases, you can also write your own argument matchers.
The easiest thing you can do is injecting another collaborator to the service which will transform payload to Entity. This way you can keep control on object creation (Inversion of Control). Something like the example below injected to the ServiceClass should do the job:
interface PayloadTransformer {
public Entity transform(String payload);
}
This way your code will be easy to test and you split responsibilities which is usually a good thing. Have a look on Single Responsibility principle
Pushing transformation logic down to dao is almost never a good idea.
BTW. you can write else if without additional brackets and indentations. It's more readable like:
if (a) {
// do something
} else if (b) {
// do something
} else {
// do something
}
The last advice ServiceClass is really poor name for class. The word class is redundant here. Just name it Service, EntityService, MessageService or something which fits your case well.
I wouldn't name field with suffix *Interface as well. Underneath is some implementation injected, I assume. Better name it entityDao or just dao. It's up to you though :)
If you use a test framework like PowerMock, you can invoke private constructors and private methods in your test. This makes it easy to inject mock objects like a mock DAOInterface so you can retrieve it later and test it's been called.
For example, in PowerMock, to call a private constructor:
public class ServiceClass{
#Autowire
private final DAOInterface dao;
public ServiceClass() {
}
private ServiceClass(DAOInterface dao) {
this.dao = dao;
}
}
You simply do:
PrivateConstructorInstantiationDemo instance = WhiteBox.invokeConstructor(
PrivateConstructorInstantiationDemo.class,
new MockDAOInterface() );
So if you're using a dependency inject framework like above, this dovetails nicely. You don't normally have the dependency injection working during test, since it usually requires booting a large chunk of code with a lot of configuration.
By adding a single private constructor, you avoid breaking encapsulation, but you can still inject your mock object into the code during test with a test framework like PowerMock. This is considered best practice.
You could break encapsulation and add publicly accessible methods or ctors to the SeviceClass, but if you don't need them for your design it's not good practice to add them only for test. That's why people put such effort into bypassing encapsulation in frameworks like Mockito and PowerMock. It's not just a dodge around private code, it's because you want to keep the encapsulation while still being able to test.
EDIT:
If you're not familiar with making mock objects, you should do some Google searches on the subject. It's very common and a good skill to have. With the above code, you could make your own mock object. But making mocks is so common that most test frameworks will do this for you.
For example, in PowerMock, I just looked at their page on making mocks here. You can make a mock like this
DAOInteface myMock = createMock(DAOInterface.class);
You can then ask the mock to verify that methods are called:
expect(myMock.someMethod());
Now the mock 'expects' that method to be called, and if it isn't, it'll generate an error for your test. Pretty sweet actually.
You can also return values from a call:
expect(myMock.insert()).andReturn("Test succeeded");
so your code would then see the value "Test succeeded" when it called that method. I don't see that 'insert' does return a value, that's just an example.

Unexpected method call while doing the unit testing with EasyMock

I am testing mail functionality in my code with the UnitilsJUnit4 and EasyMock.
My code is like this..
public void prepare(MimeMessage mimeMessage) {
// some code ..
MimeMessageHelper message = new MimeMessageHelper( mimeMessage, true );
// some mail settings ..
}
when I am testing the method prepare, it is giving the below exception.. but the method it is showing below is from the Spring framework class.
java.lang.AssertionError:
Unexpected method call setContent(javax.mail.internet.MimeMultipart#6e616e61):
setContent(javax.mail.internet.MimeMultipart#2dda2dda): expected: 1, actual: 0
at $javax.mail.internet.MimeMessage$$EnhancerByCGLIB$$614de43f.setContent(<generated>)
at org.springframework.mail.javamail.MimeMessageHelper.createMimeMultiparts(MimeMessageHelper.java:344)
at org.springframework.mail.javamail.MimeMessageHelper.<init>(MimeMessageHelper.java:290)
at org.springframework.mail.javamail.MimeMessageHelper.<init>(MimeMessageHelper.java:247)
at org.springframework.mail.javamail.MimeMessageHelper.<init>(MimeMessageHelper.java:226)
Please help me to resolve the above issue.. how to test my method?
I know this was written a long time ago, but I just encountered this exact same problem.
If you can mock the MimeMessageHelper in some form you can easily test the code. I did this by creating an interface that simply supplies back the MimeMessageHelper class and adding that as a dependency to the class I was testing.
Interface:
public interface MimeMessageHelperProvider {
MimeMessageHelper getMimeMessageHelper(MimeMessage mimeMessage);
}
Implementation:
public class MimeMessageHelperProviderImpl implements MimeMessageHelperProvider {
#Override
public MimeMessageHelper getMimeMessageHelper(MimeMessage mimeMessage) {
return new MimeMessageHelper(mimeMessage);
}
}
Now you can wire in the MimeMessageHelperProvider and simply mock that interface to have it return you an instance you can verify against.
You seem to be mocking the wrong thing. You're mocking the Mail API when you should be mocking the Spring class, since that's what you interact with directly. The way you're doing it now, you're effectively testing the Spring class along with your own, which isn't really what you want.
You need to mock the MimeMessageHelper. You can't inject it because it takes mimeMessage in the constructor. So to do this you need something like PowerMock.
From the documentation:
Use the #RunWith(PowerMockRunner.class) annotation at the
class-level of the test case.
Use the #PrepareForTest(ClassThatCreatesTheNewInstance.class)
annotation at
the class-level of the test case.
Use
PowerMock.createMock(NewInstanceClass.class) to create a mock
object
of the class that should be constructed (let's call it
mockObject).
Use
PowerMock.expectNew(NewInstanceClass.class).andReturn(mockObject)
to
expect a new construction of an object of type
NewInstanceClass.class but instead return the mock object.
Use
PowerMock.replay(mockObject, NewInstanceClass.class) to change the
mock object and class to replay mode, alternatively use the
PowerMock.replayAll() method.
Use PowerMock.verify(mockObject,
NewInstanceClass.class) to change the mock object and class to
verify mode, alternatively use the PowerMock.verifyAll() method.
Obviously, I don't really know what you're trying to test, but your test would look something like:
#RunWith(PowerMockRunner.class)
#PrepareForTest(MessagePreparer.class)
public class MessagePreparerTest {
#Test
public void testPrepare() {
MimeMessage mockMessage = PowerMock.createMock(MimeMessage.class);
MimeMessageHelper mockMessageHelper = PowerMock.createMock(MimeMessageHelper.class);
PowerMock.expectNew(MimeMessageHelper.class,
mockMessage, true).andReturn(mockMessageHelper);
// ...set other expectations
PowerMock.replay(mockMessage, mockMessageHelper, MimeMessageHelper.class);
MessagePreparer messagePreparer = new MessagePreparer();
messagePreparer.prepare(mockMessage);
PowerMock.verify(mockMessage, mockMessageHelper, MimeMessageHelper.class);
}
}

mock https request in java

Let's say I'm writing an application and I need to be able to do something like this:
String url = "https://someurl/";
GetMethod method = new GetMethod(URLEncoder.encode(url));
String content = method.getResponseBodyAsString();
Is there a way to provide a mock server that would let me handle the https request? What I'm looking for is a way to write unit tests, but I need to be able to mock the part that actually goes out to https://someurl so I can get a known response back.
Take a look at jadler (http://jadler.net), an http stubbing/mocking library I've been working on for some time. The 1.0.0 stable version has been just released, it should provide the capabilities you requested:
#Test
public void getAccount() {
onRequest()
.havingMethodEqualTo("GET")
.havingURIEqualTo("/accounts/1")
.havingBody(isEmptyOrNullString())
.havingHeaderEqualTo("Accept", "application/json")
.respond()
.withTimeout(2, SECONDS)
.withStatus(200)
.withBody("{\"account\":{\"id\" : 1}}")
.withEncoding(Charset.forName("UTF-8"))
.withContentType("application/json; charset=UTF-8");
final AccountService service = new AccountServiceRestImpl("http", "localhost", port());
final Account account = service.getAccount(1);
assertThat(account, is(notNullValue()));
assertThat(account.getId(), is(1));
}
#Test
public void deleteAccount() {
onRequest()
.havingMethodEqualTo("DELETE")
.havingPathEqualTo("/accounts/1")
.respond()
.withStatus(204);
final AccountService service = new AccountServiceRestImpl("http", "localhost", port());
service.deleteAccount(1);
verifyThatRequest()
.havingMethodEqualTo("DELETE")
.havingPathEqualTo("/accounts/1")
.receivedOnce();
}
You essentially have two options:
1. Abstract the call to the framework and test this.
E.g. refactor the code to allow you to inject a mock implementation at some point. There are many ways to do this. e.g. create a getUrlAsString() and mock that. (also suggested above). Or create a url getter factory that returns a GetMethod object. The factory then can be mocked.
2. Start up a app server as part of the test and then run your method against it. (This will be more of an integration test)
This can be achieved in an number of ways. This can be external to the test e.g. the maven jetty plugin. or the test can programmatically start up the server. see: http://docs.codehaus.org/display/JETTY/Embedding+Jetty
Running it over https will complicate this but it will still be possible with self signed certs. But I'd ask yourself - what exactly you want to test? I doubt you actually need to test https functionality, its a proven technology.
Personally I'd go for option 1 - you are attempting to test functionality of an external library. That is usually unnecessary. Also it's good practice to abstract out your dependencies to external libraries.
Hope this helps.
If you are writing a unit test, you dont want any external dependencies. from the api,
GetMethod
extends
HttpMethod
so you can easily mock it with your favorite mocking library. Your
method.getResponseBodyAsString()
call can be mocked to return any data you want.
You can wrap that code in some class and have WebClient.getUrl() and then mock (e.g. jmock) that method to return stored files - say
expectation {
oneOf("https://someurl/"), will(returnValue(someHTML));
}
Take a look at JWebUnit http://jwebunit.sourceforge.net/
Here is an example of a test...Its really quite intuitive.
public class ExampleWebTestCase extends WebTestCase {
public void setUp() {
super.setUp();
setBaseUrl("http://localhost:8080/test");
}
public void test1() {
beginAt("/home");
clickLink("login");
assertTitleEquals("Login");
setTextField("username", "test");
setTextField("password", "test123");
submit();
assertTitleEquals("Welcome, test!");
}
}
You could always launch a thttpd server as part of your unit test to serve the requests locally. Though, ideally, you have a well tested GetMethod, and then you can just mock it, and not have to actually have a remote server around for ALL of your tests.
Resources
thttpd: http://www.acme.com/software/thttpd/
To what extend are you interested in mocking this "Get" call, because if you are looking for a general purpose mocking framework for Java which integrates well with JUnit and allows to setup expectations which are automatically asserted when incorporated into a JUnit suite, then you really ought to take a look at jMock.
Now without more code, it's hard to determine whether this is actually what you are looking for, but a (somewhat useless) example, of something similar to the example code you wrote, would go something like this:
class GetMethodTest {
#Rule public JUnitRuleMockery context = new JunitRuleMockery();
#Test
public void testGetMethod() throws Exception {
// Setup mocked object with expectations
final GetMethod method = context.mock(GetMethod.class);
context.checking(new Expectations() {{
oneOf (method).getResponseBodyAsString();
will(returnValue("Response text goes here"));
}});
// Now do the checking against mocked object
String content = method.getResponseBodyAsString();
}
}
Use xml mimic stub server, that can simulate static http response based on request parameters, headers, etc. It is very simple to configure and use it.
http://xmlmimic.sourceforge.net/
http://sourceforge.net/projects/xmlmimic/

Categories