I'm writing a Junit to test the following method in Client.java:
public FSDataInputStream getObj(String hName, Path p) throws IOException {
String myKey = pathToKey(hName, p);
FileStatus status = memoryCache.getStatus(p.toString());
if (status == null) {
status = getStatus(hName, p, "getObject");
}
if (status.isDirectory()) {
throw new FileNotFoundException("Can't open " + path
+ " because it is a directory");
}
InputStream inputStream = new InputStream(bucket, myKey,
status.getLen(), client, readAhead, inputPolicy);
return new FSDataInputStream(inputStream);
}
Initially I want to test if status == null then getStatus() is invoked and if status.isDirectory(), the FileNotFoundException is thrown
I'm new to Junit so not completely sure what I'm at but to the best of my knowledge I think I need to mock the following:
List item
Client
status
inputStream
possibly memoryCache
So far this is what I've got:
#Before
public final void before() {
private COSAPIClient myClient;
private String myBucket;
FileStatus myStatus;
InputStream myInputStream;
myClient = PowerMockito.mock(AmazonS3.class);
myInputStream = PowerMockito.mock(InputStream.class);
myFileStatus = PowerMockito.mock(FileStatus.class);
}
#Test
public void getObjTest() throws Exception {
URI uri = new URI("xyz://aa-bb-cc/data7-1-23-a.txt");
String hName = "xyz://aa-bb-cc/";
Path p = new Path("cos://aa-bb-cc/data7-1-23-a.txt");
Configuration conf = new Configuration();
myClient = spy(new Client(uri, conf));
myStatus = spy(new FileStatus());
myMemoryCache.getStatus(p.toString());
InputStream = spy(new InputStream(myBucket, objectKey, 300, myClient, 12345678910L, myInputPolicy));
}
It returns a NullPointerError at this line in my program:
FileStatus status = memoryCache.getStatus(p.toString());
I wonder is anybody could advice if/what I'm doing wronfg and how I should go about resolving this?
First, the real answer: step back for a moment. Don't start with JUnit and Mockito and your production code as input. Rather have a look into a tutorial (like here) that step-by-step explains all the relevant elements and how to "bring" them together.
In your case, the are various problems with your code:
Why are you using PowerMock? Try to go with "plain vanilla" Mockito. If your production code is so that it requires PowerMock, rather consider to rework your production instead of turning to PowerMock.
You seem to really not know where/how to apply mocking. In other words: you only mock the elements that you need to control when running your code under test. And you only use mocking, if you can't control them otherwise. Meaning: you almost never mock a list - you simply create a "normal" list to then add the things that this list should contain.
Creating a mock allows to invoke methods on that mock object. But by default, any method that returns something will return null (or maybe an empty collection, or 0 for primitive return types, see here for details). Thus you rather need a statement such as when(mockedCache.getStatus("some string")).thenReturn(someResult).
Related
I have a class which send video as mp4 file to user (Http request/response)
I want to Mock method with main logic to test it. My code
public StreamingOutput videoAsStream(final String videoUrl) {
try {
final URL url = new URL(videoUrl);
return output -> {
try(final InputStream inputStream = url.openConnection().getInputStream()){
IOUtils.copy(inputStream,output);
output.close();
}
};
} catch (final MalformedURLException e) {
log.error("Url exception for url {}",videoUrl);
throw new UncheckedIOException(e);
}
}
What is my way to mock this logic?
The problem is, that URL is final, so you will have to use at least Mockito 2 to mock it. If you are ready to do that, I see two possibilities:
a) Give the url into the method and not the string, thus allowing you to put a mocked url in there. That would be the most simply method. You could also then create a 2nd convenience method that creates said URL from a string. Those two methods will be easier to test because their scope is smaller.
b) Extract the final URL url = new URL(videoUrl); part into a new class, for example a URL Factory, then mock that to return a mocked URL object in your test.
As soon as you produce stuff with "new" inside your method, this method can become harder to test, because you now cannot separate this test from this object generation.
AFAIK, you can't mock final and static methods/classes using mockito. you would have to depend on PowerMockito. I am currently not able to test your method but if you want to mock final/static, you can do as
first, Add the final/static classes to #PrepareForTest then
InputStream mockInputStream = Mockito.mock(InputStream.class);
OutputStream mockOutputStream = Mockito.mock(OutputStream.class);
PowerMockito.mockStatic(IOUtils.class);
Mockito.when(IOUtils.copy(mockInputStream, mockOutputStream)).thenReturn(1L);
Mockito.doNothing().when(mockOutputStream).close();
Let me know if this does not work for you.
I need to mock a method in a java class that is like this:
public class Helper{
public static message(final String serviceUrl){
HttpClient httpclient = new HttpClient();
HttpMethod httpmethod = new HttpMethod();
// the below is the line that iam trying to mock
String code = httpClient.executeMethod(method);
}
}
I have tried to write the junit in groovy, but not able to do so as grrovy meta-proggraming techniques do not apply for java classes. On my research, i have found out that JMockit is a good framework that can also mock objects that are created using new constructor.
Can somebody show me how to write the unittest for the above class either in java or in groovy.
Advanced Thanks
this is the test case that i have tried so far using jmockit, but does not work..
void testSend(){
def serviceUrl = properties.getProperty("PROP").toString()
new Expectations(){
{
HttpClient httpClient=new HttpClient();
httpClient.executeMethod(); returns null;
}
};
def responseXml = Helper.sendMessage(requestXml.toString(), serviceUrl)
}
With jmockit you can also mock instance creation. I prefer slightly different technique:
#Test
public void testFoo(#Mocked final HttpClient client) {
new Expectations() {{
// expect instance creation and return mocked one
new HttpClient(... ); returns(client)
// expect invocations on this mocked instance
client.invokeSomeMethid(); returns(something)
}};
helper.message(serviceUrl)
}
The java version of your test case would look like:
#Test
public void testSend() throws IOException {
final String serviceUrl = "http://google.com/";
new Expectations(){
// these bits are important as they tell Jmockit what classes to mock
#Mocked HttpClient client ;
#Mocked GetMethod method;
{
HttpClient httpClient= new HttpClient() ;
HttpMethod method = new GetMethod(withEqual(serviceUrl));
try {
httpClient.executeMethod(method);
} catch (IOException e) {
// not going to happen
}
result = 200;
}
};
// run the test and assert something
Assert.assertEquals(200, Helper.message(serviceUrl));
}
This is available on github.com, note I used httpClient 3.1 to implement your message method, I'm guessing that isn't quite right, but should be enough to answer the question.
If you can prep a simple grails project with your test case in I'm sure I can figure out what the issue is.
Update: I've been playing with a toy grails project locally and haven't managed to configure jmockit correctly. The key thing with jmockit is to ensure it is before junit on the classpath, but since junit is shipped in grails I can't find away to get jmockit in the right place.
thanks for raising the question, with Spring-web-3.2.2 (which uses httpclient-4.0.1), my code looks like this:
new NonStrictExpectations(){
#Mocked(methods={"executeMethod"})
ClientHttpRequest mocked_req;
#Mocked(methods={"getBody"})
ClientHttpResponse mocked_res;
{
byte[] buf = (
"<example_xml><person><name>Johnson</name><age>20</age></person></example_xml>"
).getBytes();
mocked_req.execute();
mocked_res.getBody(); returns(new ByteArrayInputStream(buf));
}
};
RestTemplate mytemplate = new RestTemplate();
obj = mytemplate.getForObject(.....);
assertEquals("returned and parsed obj should be equal to this one", expectedObj, obj);
I'm trying to write JUnit tests for my code but with in some of my methods other methods are called. Is it possible to mock these calls out?
E.g.
s3FileWrite(File file, Status status)
{
S3 s3 = new S3(file.getName, s3Service)
String key = s3.getKey();
String bucket = s3.getBucket();
File tmp = new File("tmp/" + s3.getName());
writeFile(key, bucket, tmp, status); //local method call I want to mock out
}//awsFileWrite
The writeFile method is what I want to mock out and it's part of the class I am testing, but I don't know how to mock it out. I thought mocking out the class I'm testing and then adding the call to my expectations would do it but it still calls the method.
Can anyone give me some advice on what to do here please?
EDIT:
My JMock code looks like this:
#Test
public void testS3FileWrite()
{
fileName = context.mock(File.class);
s3Service = context.mock(FileDataAccessor.class);
s3 = context.mock(S3.class);
reportWriter = context.mock(ReportWriter.class);
try
{
context.checking(new Expectations(){{
oneOf(fileMetaData).getKey();
will(returnValue("s3Key"));
oneOf(fileMetaData).getBucketName();
will(returnValue("BucketName"));
oneOf(fileMetaData).getName();
will(returnValue("TempFile"));
((MethodClause) oneOf (any(File.class))).method("File").with(same("tmp/TempFile"));
oneOf(reportWriter).writeFile(with(same("s3Key")),
with(same("BucketName")),
with(any(File.class),
with(same(Status.OK)));
}});//Expectations
}
catch (Exception e)
{
ErrorStatus.debug("Exception in ReportTest.testS3FileWrite: " + e);
}//try-catch
ReportWriter test = new ReportWriter(status);
test.awsFileWrite(fileName, Status.OK);
}//testAWSFileWrite
PowerMock lets you partially mock classes, but it's designed for EasyMock not JMock. In any case, this is not the best approach.
Add a new class FileWriter and move the writeFile method to it, then in your class under test,
delegate to one:
// default implementation, can be replaced in tests
FileWriter fileWriter = new FileWriter();
writeFile(key, bucket, tmp, status) {
fileWriter.write(key, bucket, tmp, status);
};
In your test code, overwrite the fileWriter field in a the class under test (add a setter or make the field protected) with a mock FileWriter.
I've looked at the following question and it is not the same as mine:
jMockit: How to expect constructor calls to Mocked objects?
This question is similar but the answer is not helpful to me:
How to mock the default constructor of the Date class with JMockit?
What I am trying to do is mock a constructor call to java.util.zip.ZipFile, specifically the one that has a java.io.File argument. I would like for the constructor to return an instance of a different ZipFile, one I will instantiate with the constructor that only takes a String argument.
This constructor call takes place inside a method under test, so I can't inject the ZipFile I want as a parameter.
For example, the code looks something like this:
public void whatever() {
//some code
//some more code
foo();
//yet more unrelated code
}
private Blah foo() {
ZipFile zf;
//a bunch of code we don't care about
zf = new ZipFile(someFile);// I want to give it a known zipfile! mock this!
// some more code we don't care about
Enumeration<?> entries = zf.entries();
ZipEntry entry = (ZipEntry) entries.nextElement();
InputStream is = zf.getInputStream(entry)
//maybe some other calls to the ZipFile
// do something else
}
My first thought was to do the following with static partial mocking:
final ZipFile test = new ZipFile("path/to/actual.zip");
new NonStrictExpectations() {
#Mocked("(java.io.File)")
ZipFile zf;
{
new ZipFile((File) any); result = test;
}
};
But this won't work as indicated by this line in the tutorial: constructors have void return type, so it makes no sense to record return values for them
My second thought was to try the following:
new NonStrictExpectations() {
{
newInstance("java.util.zip.ZipFile", new File("path/to/actual.zip"));
}
};
But this throws the following when trying to initialize the file:
java.util.zip.ZipException: error in opening zip file
at java.util.zip.ZipFile.open(Native Method)
at java.util.zip.ZipFile.<init>(Unknown Source)
at java.util.zip.ZipFile.<init>(Unknown Source)
My third thought was to use a #MockClass as below:
#Before
public void setUp() throws Exception {
Mockit.setUpMocks(MockedZipFile.class);
}
#After
public void tearDown() {
Mockit.tearDownMocks();
}
#MockClass(realClass=ZipFile.class)
public static class MockedZipFile {
public ZipFile it;
#Mock
public void $init(File f) throws ZipException, IOException {
it = new ZipFile("path/to/actual.zip");//this is what would be called
}
}
But this hoses some other mocks I have that load a configuration file for a different part of my test class. Not to mention I will want different zip files for different test cases.
I suppose I could mocking everything the ZipFile would do, but this would quickly become a giant pain as it's called lots of places, it's output would be need to be mocked, etc, etc. Refactoring to try to make this accessible would be awkward, as the code that uses the ZipFile is internal to the code and the public methods don't really care about it.
I have a feeling there is a way for JMockit to allow this (giving a particular instance of an object when a constructor is called), but I can't figure it out. Does anyone have any ideas?
EDIT: I tried the method suggested by #Rogerio, but I have a new error. Here's my setup:
final ZipFile test = new ZipFile("path/to/actual.zip");
new NonStrictExpectations() {
ZipFile zf;
{
zf.entries();
result = test.entries();
zf.getInputStream((ZipEntry) any);
result = new Delegate() {
InputStream getInputStream(ZipEntry entry) throws IOException {
return test.getInputStream(entry);
}
};
}
};
but I get the following stack trace:
java.lang.InternalError
at path.to.test.ExtractDataTest$1.<init>(ExtractDataTest.java:61)
at path.to.test.ExtractDataTest.setUp(ExtractDataTest.java:61)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
where line 61 is the new NonStrictExpectations() { line.
I really want to say "instead of mocking this object, substitute this other object of the same type". Maybe I have expressed that poorly.
EDIT2: I figured I should include version numbers:
Using Eclipse 3.6.1
Java 1.6.0_26
JMockit 0.999.10
JMockit can mock the ZipFile class, but it interferes with class loading since the JarFile subclass is used by the JVM all the time (whenever it loads a class from a jar file in the classpath). Currently, there is no easy way to avoid this interference (there is a plan to "fix" this, but it will take time).
However, this particular test case isn't very suited for a mocking tool anyway. Instead, I would recommend setting up the test so that it provides an actual zip file with the desired contents in the proper place.
(another edit)
I just applied a change to JMockit (for release 0.999.12) which allows the following test to pass, provided there is a test.zip file in the working dir, and it contains a text file whose first line is "test":
#Test
public void mockZipFile() throws Exception
{
final ZipFile testZip = new ZipFile("test.zip");
new NonStrictExpectations() {
#Capturing #Injectable ZipFile mock;
{
mock.entries(); result = testZip.entries();
mock.getInputStream((ZipEntry) any);
result = new Delegate() {
InputStream delegate(ZipEntry e) throws IOException {
return testZip.getInputStream(e);
}
};
}
};
ZipFile zf = new ZipFile("non-existing");
ZipEntry firstEntry = zf.entries().nextElement();
InputStream content = zf.getInputStream(firstEntry);
String textContent = new BufferedReader(new InputStreamReader(content)).readLine();
assertEquals("test", textContent);
}
However, I would still recommend not using a mocking API for cases like this. Instead, use a real file.
This probably won't help you, but if you were using Mockito or EasyMock, you could add PowerMock, which allows you to mock the construction of new objects in your code under test.
I have a class which calls out to an existing web service. My class properly handles valid results as well as fault strings generated by the web service. The basic call to the web service looks something like this (although this is simplified).
public String callWebService(final String inputXml)
{
String result = null;
try
{
StreamSource input = new StreamSource(new StringReader(inputXml));
StringWriter output = new StringWriter();
_webServiceTemplate.sendSourceAndReceiveToResult(_serviceUri, input, new StreamResult(output));
result = output.toString();
}
catch (SoapFaultClientException ex)
{
result = ex.getFaultStringOrReason();
}
return result;
}
Now I need to create some unit tests which test all of the success and failure conditions. It cannot call the actual web service, so I was hoping there were mock objects available for the client side of Spring-WS. Does anyone know of an mock objects available for the WebServiceTemplate or any related classes? Should I just attempt to write my own and modify my class to use the WebServiceOperations interface vs. WebServiceTemplate?
Michael's answer is very close, but here is the example that works.
I already use Mockito for my unit tests, so I am familiar with the library. However, unlike my previous experience with Mockito, simply mocking the return result does not help. I need to do two things to test all of the use cases:
Modify the value stored in the StreamResult.
Throw a SoapFaultClientException.
First, I needed to realize that I cannot mock WebServiceTemplate with Mockito since it is a concrete class (you need to use EasyMock if this is essential). Luckily, the call to the web service, sendSourceAndReceiveToResult, is part of the WebServiceOperations interface. This required a change to my code to expect a WebServiceOperations vs a WebServiceTemplate.
The following code supports the first use case where a result is returned in the StreamResult parameter:
private WebServiceOperations getMockWebServiceOperations(final String resultXml)
{
WebServiceOperations mockObj = Mockito.mock(WebServiceOperations.class);
doAnswer(new Answer()
{
public Object answer(InvocationOnMock invocation)
{
try
{
Object[] args = invocation.getArguments();
StreamResult result = (StreamResult)args[2];
Writer output = result.getWriter();
output.write(resultXml);
}
catch (IOException e)
{
e.printStackTrace();
}
return null;
}
}).when(mockObj).sendSourceAndReceiveToResult(anyString(), any(StreamSource.class), any(StreamResult.class));
return mockObj;
}
The support for the second use case is similar, but requires the throwing of an exception. The following code creates a SoapFaultClientException which contains the faultString. The faultCode is used by the code I am testing which handles the web service request:
private WebServiceOperations getMockWebServiceOperations(final String faultString)
{
WebServiceOperations mockObj = Mockito.mock(WebServiceOperations.class);
SoapFault soapFault = Mockito.mock(SoapFault.class);
when(soapFault.getFaultStringOrReason()).thenReturn(faultString);
SoapBody soapBody = Mockito.mock(SoapBody.class);
when(soapBody.getFault()).thenReturn(soapFault);
SoapMessage soapMsg = Mockito.mock(SoapMessage.class);
when(soapMsg.getSoapBody()).thenReturn(soapBody);
doThrow(new SoapFaultClientException(soapMsg)).when(mockObj).sendSourceAndReceiveToResult(anyString(), any(StreamSource.class), any(StreamResult.class));
return mockObj;
}
More code may be required for both of these use cases, but they work for my purposes.
actually i don't know if there exist preconfigured Mock Objects, but i doubt there are configured for all your "failure Conditions", so you can create a special Spring ApplicationContext for your JUnit Test with a substitute or work with a mock Framework, it's not that hard :-)
i used the Mockito Mock Framework for the example (and typed it quickly), but EasyMock or your preferred mock framework should do it as well
package org.foo.bar
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
public class WebserviceTemplateMockTest {
private WhateverTheInterfaceIs webServiceTemplate;
private TestClassInterface testClass;
private final String inputXml = "bar";
#Test
public void testClient(){
//
assertTrue("foo".equals(testClass.callWebService(inputXml));
}
/**
* Create Webservice Mock.
*/
#Before
public void createMock() {
// create Mock
webServiceTemplate = mock(WhateverTheInterfaceIs.class);
// like inputXml you need to create testData for Uri etc.
// 'result' should be the needed result data to produce the
// real result of testClass.callWebService(...)
when(webServiceTemplate.sendSourceAndReceiveToResult(Uri, inputXml, new StreamResult(output))).thenReturn(result);
// or return other things, e.g.
// .thenThrow(new FoobarException());
// see mockito documentation for more possibilities
// Setup Testclass
TestClassImpl temp = new TestClassImpl();
temp.setWebServiceTemplate(generatedClient);
testClass = temp;
}
}