I have the following problem using Mockito for unit testing:
I have this method:
#Override
public void handle(HttpExchange httpRequest) throws IOException {
Object[] outputResult = processRequest(httpRequest);
String response = (String) outputResult[0];
Integer responseCode = (Integer) outputResult[1];
httpRequest.sendResponseHeaders(responseCode, response.length());
OutputStream os = httpRequest.getResponseBody();
os.write(response.getBytes());
os.close();
}
And I want only to test this method, not the processRequestMethod that is called internally (that I would like to test separately in anthoer test), so I need to mock it and to check at the end of the test that the methods write and close of the OutputStream class have been called.
I have tried two ways, but no luck with none of them:
#Test
public void handleTest() throws IOException {
RequestHandler requestHandler=mock(RequestHandler.class);
String response = "Bad request";
int responseCode = HttpURLConnection.HTTP_BAD_REQUEST;
Object[] result={response,responseCode};
when(requestHandler.processRequest(anyObject())).thenReturn(result);
when (httpExchange.getResponseBody()).thenReturn(outputStream);
requestHandler.handle(httpExchange);
Mockito.verify(outputStream,times(1)).write(anyByte());
Mockito.verify(outputStream,times(1)).close();
}
With the code above, the processRequest method is not called, but neither is the handle method that I want to test, so the test is failing in the line:
Mockito.verify(outputStream,times(1)).write(anyByte());
Saying that this method was not called at all.
However if I add the parameter CALL_REAL_METHODS when creating the mock, like this:
#Test
public void handleTest() throws IOException {
RequestHandler requestHandler=mock(RequestHandler.class,CALLS_REAL_METHODS);
String response = "Bad request";
int responseCode = HttpURLConnection.HTTP_BAD_REQUEST;
Object[] result={response,responseCode};
when(requestHandler.processRequest(anyObject())).thenReturn(result);
when (httpExchange.getResponseBody()).thenReturn(outputStream);
requestHandler.handle(httpExchange);
Mockito.verify(outputStream,times(1)).write(anyByte());
Mockito.verify(outputStream,times(1)).close();
}
Then the processRequest method that I want to skip is actually called when the method executes this line:
when(requestHandler.processRequest(anyObject())).thenReturn(result);
Any clues of what can be wrong?
in your test instead of
RequestHandler requestHandler=mock(RequestHandler.class,CALLS_REAL_METHODS);
use Mockito.spy():
RequestHandler requestHandler=spy(RequestHandler.class);
doReturn(result).when(requestHandler).processRequest(httpRequest);
you may want the doReturn().when() form rather than the when().thenReturn() because the first does not execute the method whereas the latter does.
On the other hand I'd prefer to move processRequest() to another class where you can inject an instance of into RequestHandler which would make mocking more straight...
Related
I have a unit test (simplified version below) that tests a Netty handler.
I create an EmbeddedChannel with an instance of the handler.
The caller writes a string to the channel
The handler receives the string, reverses and writes it back.
The caller reads the return values from the channel and verifies it is the reverse of the sent string.
This works perfectly. However, I need to verify the number of invocations on the channel, so I created a spy of the channel but mocked no methods, since I don't want to change the behavior of the class, just count invocations.
Now the test fails. 2 of the assertions succeed. They are a test to make sure the handler was called, and a test to verify the number of times a method of the channel was called. However, the final read response is always null when the spy is used.
I was under the impression that a solitary spy with no other mocking would not affect the behavior of the spied object, but obviously it does. The [nonPower] Mockito docs indicate the objects are copied which might cause this issue, but the PowerMockito docs are not as specific.
I am using Netty 4.1.6.Final and Powermock 1.5.6.
UPDATE: I managed to get the test working but it's a bit of wonky workaround. See the new method testSpiedEmbeddedChannel2. The workaround is that I create a non-spied channel (ecx), then a the spied channel (ec) using ecx. I issued the write on ec, and the read using ecx. This means if I try to verify methods used in the read, they will not be counted.
Here's the code with the successful and failing tests.
#RunWith(PowerMockRunner.class)
#PowerMockIgnore({"javax.management.*"})
#PrepareForTest(EmbeddedChannel.class)
public class TestEmbeddedChannel {
class EchoHandler extends ChannelDuplexHandler {
final AtomicInteger reads = new AtomicInteger(0);
#Override
public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
reads.incrementAndGet();
final String value = (String)msg;
final String response = new StringBuilder(value).reverse().toString();
ctx.channel().writeAndFlush(response);
}
}
#Test
public void testEmbeddedChannel() { // PASSES
final EchoHandler handler = new EchoHandler();
final EmbeddedChannel ec = new EmbeddedChannel(handler);
ec.writeInbound("Hello World");
final String response = ec.readOutbound();
Assert.assertEquals(1, handler.reads.get());
Assert.assertEquals("dlroW olleH", response);
}
#Test
public void testSpiedEmbeddedChannel() { // FAILS
final EchoHandler handler = new EchoHandler();
final EmbeddedChannel ec = spy(new EmbeddedChannel(handler));
ec.writeInbound("Hello World");
final String response = ec.readOutbound();
verify(ec, times(2)).isOpen(); // OK
Assert.assertEquals(1, handler.reads.get()); // OK
Assert.assertEquals("dlroW olleH", response); // FAILS
}
#Test
public void testSpiedEmbeddedChannel2() { // PASSES
final EchoHandler handler = new EchoHandler();
final EmbeddedChannel ecx = new EmbeddedChannel(handler);
final EmbeddedChannel ec = spy(ecx);
ec.writeInbound("Hello World");
final String response = ecx.readOutbound(); // Read using non-spied channel
verify(ec, times(2)).isOpen();
Assert.assertEquals(1, handler.reads.get());
Assert.assertEquals("dlroW olleH", response);
}
}
Thanks for any guidance here.
I wanted to test the IOException and IllegalArgumentException thrown by properties.load(in) method. As per the documentation here OracleDoc it says the load method throws IOException - if an error occurred when reading from the input stream. IllegalArgumentException - if the input stream contains a malformed Unicode escape sequence.
Here is my code:
public class PropertiesRetriever {
private String foo;
private String foo1;
private Properties properties;
/**
* Injects the properties file Path in the {GuiceModule}
* Calls {#link PropertiesRetriever#loadPropertiesPath(String) to load the
* properties file.
*/
#Inject
public PropertiesRetriever(#Named("propertiesPath") String propertiesPath, Properties properties)
throws IOException {
this.properties = properties;
loadPropertiesPath(propertiesPath);
}
/**
* Loads the properties file as inputstream.
*
*/
public void loadPropertiesPath(String path) throws IOException {
InputStream in = this.getClass().getResourceAsStream(path);
properties.load(in);
}
Here, a method:
properties.load(in)
throws IOException and IllegalArgumentException. I wanted to test this methods in JUnit testing. Is there anyway I can call these methods.
You can do it by refactoring your code a little. That and use Mockito or some other mocking framework to create an InputStream that behaves as you desire (throw exceptions):
public void loadPropertiesPath(String path) throws IOException {
// Always close streams you open!
try (InputStream in = getIStream(path)) {
properties.load(in);
}
}
private InputStream getIStream(String path) {
InputStream in = this.getClass().getResourceAsStream(path);
return in;
}
You can use mockito to create a partial mock of your object; mock getIStream(String) to return a mock InputStream. Set up the mock to throw the exception you want when InputStream::read(byte[]) gets called.
If you do not want to use PowerMock then you can change the visibility of getIStream(String) to default. Then plain mockito will do the job:
#Test
public void exceptionTest() throws IOException {
PropertiesRetriever pr = new PropertiesRetriever();
PropertiesRetriever prSpy = spy(pr);
InputStream isMock = mock(InputStream.class);
doReturn(isMock).when(prSpy).getIStream(anyString());
doThrow(new IllegalArgumentException("CRASH!")).when(isMock).read(any());
prSpy.loadPropertiesPath("blah");
}
You have two choices. Either provide some test files, that will create expected errors, or pass mock of Stream to Properties retriever as parameter. So instead of propertiesPath parameter, you will have directly inputStream (this approach may just move your problem somewhere else).
If you decide to pass Stream as a parameter, there are some tips, how to mock it: Mocking Java InputStream
I'm taking Software Testing because I'm majoring in CS. The professor gave us the source code of a program made in Java to test it. I'm testing right now this method:
public static void createPanel(HttpServletRequest req, HttpServletResponse res, HttpSession hs) throws IOException
{
String panelName = req.getParameter("panelName");
String panelDescription = req.getParameter("panelDescription");
int employeeID = ((EmployeeProfile)hs.getAttribute("User Profile")).EmployeeID;
boolean result;
//Let's validate our fields
if(panelName.equals("") || panelDescription.equals(""))
result = false;
else
result = DBManager.createPanel(panelName, panelDescription, employeeID);
b = result;
//We'll now display a message indicating the success of the operation to the user
if(result)
res.sendRedirect("messagePage?messageCode=Panel has been successfully created.");
else
res.sendRedirect("errorPage?errorCode=There was an error creating the panel. Please try again.");
}
I'm using Eclipse with JUnit and mockito to test all the methods including this one. For this specific method, I want to check if the program redirects to one location or another, but I don't know how to do it. Do you have any idea? Thanks.
You can actually achieve it easily with Mockito and ArgumentCaptor:
#RunWith(MockitoJUnitRunner.class)
public class MyTest {
#Mock
private HttpServletResponse response
...
#Test
public void testCreatePanelRedirection(){
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
YourClass.createPanel(request, response, session);
verify(response).sendRedirect(captor.capture());
assertEquals("ExpectedURL", captor.getValue());
}
}
I want to test StreamDecorator class:
public interface IDecorator {
default InputStream decorateStream() {
if("gzip".equalsIgnoreCase(getEncoding())) {
return new GZIPInputStream(getInputStream());
}
return is;
}
String getEncoding();
InputStream getInputStream();
}
public class StreamDecorator implements IDecorator {
private final InputStream is;
private final String encoding;
public StreamDecorator(InputStream is, String encoding) {
this.is = is;
this.encoding = encoding;
}
public String getEncoding() {
return encoding;
}
public InputStream getInputStream() {
return is;
}
}
To test it, I have written the following test case:
#RunWith(PowerMockRunner.class)
public class TestStreamDecorator {
#Test
#PrepareForTest(value = { GZIPInputStream.class })
public void testDecorateStream() throws Exception {
InputStream mockInputStream = PowerMock.createMock(InputStream.class);
EasyMock.expect(mockInputStream.read()).andReturn(-1);
PowerMock.replay(mockInputStream);
GZIPInputStream gzip = PowerMock.createMock(GZIPInputStream.class);
PowerMock.expectNew(GZIPInputStream.class, mockInputStream).andReturn(gzip);
PowerMock.expectNew(GZIPInputStream.class, mockInputStream, 512).andReturn(gzip);
PowerMock.replay(gzip);
PowerMock.replay(GZIPInputStream.class);
StreamDecorator inStreamDecorator = new StreamDecorator(mockInputStream, "gzip");
assertEquals(gzip, inStreamDecorator.decorateStream());
PowerMock.verify(mockInputStream, gzip, GZIPInputStream.class);
}
}
When I run the unit test, I get java.io.EOFException (see below).
I know the reason for this exception -- it is because in second statement in TestStreamDecorator.testDecorateStream() method I'm returning -1 for InputStream.read().
But, my question is why is it even getting called when I have mocked the constructors (i.e. new instances)?
Also, I have tried mocking private readHeader() method of GZIPInputStream -- but getting different exception in another private method.
So, I guess, I'm doing something wrong.
===================== Exception =====================
java.io.EOFException
at java.util.zip.GZIPInputStream.readUByte(GZIPInputStream.java:268)
at java.util.zip.GZIPInputStream.readUShort(GZIPInputStream.java:258)
at java.util.zip.GZIPInputStream.readHeader(GZIPInputStream.java:164)
at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:79)
at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:91)
...
My guess is PowerMock has some issues with Java 8 default methods. Anything in that direction?
You are actually verifying the mock in your last line of test case which is why you are getting the exception
Delete last two lines of your test and add this and you test case passes
assertEquals(mockInputStream, inStreamDecorator.decorateStream());
I'm trying to test the following method
MainClass {
....
Client client;
WebTarget target;
boolean doLogin(MultivaluedMap<String, String> headers) {
client = getRestClient();
target = client.target(BASE_URL))
.path("v1/login");
MultivaluedMap<String, Object> castedHeaders = castMap(headers);//casts headers by entry.
Response loginRsp = target
.request().headers(castedHeaders)
.post(Entity.entity(buildIusLoginEntity(),
MediaType.APPLICATION_JSON_TYPE));
if (loginRsp.getStatus() != HttpServletResponse.SC_OK) {
return false;
}
return true;
}
}
Using the following test class
#Test
public void testdoLoginNegative() {
MainClass m = spy(new MainClass());
Client mockClient = mock(Client.class);
WebTarget target = mock(WebTarget.class);
Response loginRsp = Response.status(500).build();
doReturn(mockClient).when(m).getRestClient();
when(mockClient.target(anyString()).path(anyString())).thenReturn(target);
//NPE on next line.
when(target.request().headers(any(MultivaluedMap.class)).post(any(Entity.class))).thenReturn(loginRsp);// this line throws a Null pointer exception.
Assert.assertFalse(m.doIusLogin(getMockHeaders()));
}
However, my mock seems to show a null pointer exception as indicated in the source code. Any thoughts on what I could be doing wrong.. would be greatly appreciated.
You try to use deep stubbing without preparing your mock objects. Try
WebTarget target = mock(WebTarget.class, Mockito.RETURNS_DEEP_STUBS);
The difference is, that the mock without deep stubbing returns default values on method calls (usually null). If you enclose such a call with Mockito.when this does not have an effect, but if you append further calls this leads to NullPointerExceptions, e.g. in
target
.request() // return null
.headers(any(MultivaluedMap.class)) // NullPointerException
.post(any(Entity.class)))
However I would expect
mockClient
.target(anyString()) // should return null
.path(anyString())) // should throw NullPointerException
to fail too with NullPointerException, without activating deep stubs with
Client mockClient = mock(Client.class, Mockito.RETURNS_DEEP_STUBS);
Not that activating deep stubbing may be convenient for writing tests, but it can lead to strange behaviors in the tested code.