I have a simple array class with some methods such as Add(int n), AddAt(int n, int index), etc.
the addAt method calls another method from super class
public void addAt(int n, int index) {
if (checkIndex(index, size + 1)){
...
}
}
that checks if the inserted index is not out-bounded, if so the super class method prints an error message to console.
how should I test that if the message is printed? I am using JUnit4.12-beta
#Test
public void testPrint() {
ByteArrayOutputStream outContent = new ByteArrayOutputStream();
//redirect the System-output (normaly the console) to a variable
System.setErr(new PrintStream(outContent));
//call your method here
//check if your error message is in the output variable
assertEquals("your output", outContent.toString());
}
You could also use a mocking framework to mock the target object and check whether or not the target method has been called.
See for instance http://eclipsesource.com/blogs/2011/10/13/effective-mockito-part-3/
This might be a bit of an investment if you do not have such a framework in place already...
Can't you make your life simpler by raising exceptions rather than printing messages ?
In which case you can use 'expected' exceptions like here : How do you assert that a certain exception is thrown in JUnit 4 tests?
Related
I'm trying test this code using mockito, so need to mock the result as error and test the code. In this case, I've hardcoded the result as 1.
public class RetrieveData {
public int retrieveMetaData() {
int retries = 0;
int result = 0;
int MAX_RETRIES = 3;
while (retries++ < MAX_RETRIES) {
try {
result = 1;
} catch (Exception e) {
if(retries < MAX_RETRIES) {
System.out.println(" retries :" + retries );
} else {
throw e;
}
}
}
return result;
}
public static void main(String[] args) {
int result ;
RetrieveData obj = new RetrieveData();
result = obj.retrieveMetaData();
System.out.println(result);
}
}
Mockito:
import org.junit.Test;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
public class TestretrieveMetaData {
#Test
public void test_retrieveMetaData() throws Exception {
RetrieveData resultObj = mock(RetrieveData.class);
// how to add the mock for the result.
}
}
First of all, you have to understand what you intend to do!
You see, you either mock a class X ... because an instance of X is used in some class Y, and you intend to test Y. Or you intend to test class X, but then you shouldn't mock instances of X! Either you test X, or you use X for testing something else.
Assuming that you want to mock an instance of your class RetrieveData, you simply do:
RetrieveData resultObj = Mockito.mock(RetrieveData.class);
Mockito.when(resultObj.retrieveMetaData()).thenReturn(42);
So, to align with that comment by Tobb: you can't "mock" that result field alone. If at all, you can mock complete instances of your class. But as said: that only makes sense when you use that instance within another class you intend to test.
Long story short: as said, the real issue is that you are trying to use concepts that you simply do not understand (no judgement here). My recommendation: start by reading a good tutorial on Mockito. Then spent a lot of time thinking "how can I write code that I can test in reasonable ways". You are trying to start with step 10, but that won't work, because you can only do that when you made steps 1 to 9 before, and understand what they are about.
And yes, you can use a Mockito spy when you want to "partial mocking". Using that, you can test parts of X, whilst also "mocking out" other parts of X. But that is really an advanced feature, and most likely not the topic you should study first.
I'm trying to use EasyMock to test that a method runs a specific number of times but I keep getting an IllegalStateException error and I don't understand why. I'm new to EasyMock and JUnit and not very familiar with how to use them so I'm not sure what I'm doing wrong.
My code is:
FileOutputStream mockWriter;
Numbers mockByte;
#Test
public void testNumbers() throws IOException{
mockWriter = createMock(FileOutputStream.class);
mockByte = new Numbers(mockWriter);
mockByte.initByte();
expect(mockByte.generate()).times(10000);
replay(mockWriter);
}
And these are the methods initByte and generate from my Numbers class:
public void initByte() throws IOException{
File outFile = new File("NumbersOutput.txt");
FileOutputStream f = new FileOutputStream(outFile);
for(int i = 0; i < 10000; i++){
int b = generate();
f.write(b);
}
f.flush();
f.close();
}
public int generate(){
return rand.nextInt(100001);
}
The error you're getting is because nothing's calling anything on your mock.
Contrary to your naming, mockByte doesn't refer to a mock at all, so using it in an expect call like this is not going to help you. You should be expecting calls on mockWriter if anything.
However, it's not clear why you're using a mock for a stream at all, nor what the OutputStream in the Numbers constructor is used for. Your initByte() method doesn't use any state within the object other than rand. Even when that's fixed, it would probably be simplest just to use a ByteArrayOutputStream... make your API talk in terms of OutputStream instead of FileOutputStream, and it'll be much easier to test.
I suspect you should:
Remove the construction of a new FileOutputStream from the initByte method, instead writing to the stream you accept in the Numbers constructor
If your constructor parameter type is FileOutputStream, change it to OutputStream to make it cleaner and easier to test
Create a ByteArrayOutputStream in your test - you don't need mocking at all. You can then get all the bytes that have been written, and check them for whatever you want.
Think carefully about what you expect f.write(b) to do. It's only going to write a single byte, so the top 24 bits of your random number are going to be ignored. At that point, why are you choosing a number in the range [0, 10000] anyway?
I am trying my hand at writing test cases. From what I have read, my tests should fail from the start and I should strive to make tests pass. However, I find myself writing tests checking boundaries and the exceptions they should cause:
#Test(expected=NegativeArraySizeException.class)
public void testWorldMapIntInt() {
WorldMap w = new WorldMap(-1, -1);
}
#Test(expected=IndexOutOfBoundsException.class)
public void testGetnIntnInt() {
WorldMap w = new WorldMap(10,10);
Object o = w.get(-1, -1);
}
However, this test passes by default because Java will throw the exception anyway. Is there a better way to handle these kinds of expected exceptions, possibly a way that fails by default-- forcing me to strive to handle these cases?
I agree that the style you present is not so good. The problem is that it doesn't check where in the method the exception is thrown, so it's possible to get false negatives.
We usually write tests for exceptions like this:
public void testWorldMapIntInt() {
try {
WorldMap w = new WorldMap(-1, -1);
Assert.fail("should have thrown IndexOutOfBoundsException");
}
catch (IndexOutOfBoundsException e) {}
}
Expected behaviour for WorldMap is to throw an exception if (-1, -1) passed into it
Initially it doesn't do that, so your test will fail as it does not see expected exception.
You implement the code for WorldMap correctly, including throwing exception when (-1, -1) passed in.
You rerun your test, it passes.
Sound like good TDD to me!
That seems like a fair test to write. WorldMap is no standard Java class. Presumably it's your own class. Therefore the test wouldn't be passing if you hadn't already written some code. This test will force you to throw (or propagate) an appropriate exception from your class. That sounds like a good test to me, which you should write before implementing the behavior.
I personally look for mistakes like that in the WorldMap constructor and throw an IllegalArgumentException, that way you can provide a better error message, such as what the value passed in was and what the expected range is.
As for having that test fail by default, I cannot think of a reasonable way of doing that if you are going to have it actually do something (if you are writing the tests first then it should fail because the constructor won't have any code).
Agree with accepted answer, try-fail-catch idiom, although ugly and cluttering the test, is much better than #Test(expcted=...) as it might report false positives.
A while back I implemented very simple JUnit rule to deal with exception testing in both safe and readable manner:
public class DefaultFooServiceTest {
#UnderTest
private FooService fooService = new DefaultFooService();
#Rule
public ExceptionAssert exception = new ExceptionAssert();
#Test
public void shouldThrowNpeWhenNullName() throws Exception {
//given
String name = null;
//when
fooService.echo(name);
//then
exception.expect(NullPointerException.class);
}
#Test
public void shouldThrowIllegalArgumentWhenNameJohn() throws Exception {
//given
String name = "John";
//when
fooService.echo(name);
//then
exception.expect(IllegalArgumentException.class)
.expectMessage("Name: 'John' is not allowed");
}
}
See blog post and source.
By 'output steam' i mean any object which receives a sequence of bytes, or characters or whatever. So, java.io.OutputStream, but also java.io.Writer, javax.xml.stream.XMLStreamWriter's writeCharacters method, and so on.
I'm writing mock-based tests for a class whose main function is to write a stream of data to one of these (the XMLStreamWriter, as it happens).
The problem is that the stream of data is written in a series of calls to the write method, but what matters is not the calls, but the data. For example, given an XMLStreamWriter out, these:
out.writeCharacters("Hello, ");
out.writeCharacters("world!");
Are equivalent to this:
out.writeCharacters("Hello, world!");
It really doesn't matter (for my purposes) which happens. There will be some particular sequence of calls, but i don't care what it is, so i don't want to write expectations for that particular sequence. I just want to expect a certain stream of data to be written any which way.
One option would be to switch to state-based testing. I could accumulate the data in a buffer, and make assertions about it. But because i'm writing XML, that would mean making some fairly complex and ugly assertions. Mocking seems a much better way of dealing with the larger problem of writing XML.
So how do i do this with a mock?
I'm using Moxie for mocking, but i'm interested in hearing about approaches with any mocking library.
A fairly elegant strategy to test output or input streams is to use PipedInputStream and PipedOutputStream classes. You can wire them together in the set up of the test, and then check what has been written after the target method is executed.
You can work the other direction preparing some input and then let the test read this prepared data from the input stream as well.
In your case, you could just mock that "out" variable with a PipedOutputStream, and plug a PipedInputStream to it this way:
private BufferedReader reader;
#Before
public void init() throws IOException {
PipedInputStream pipeInput = new PipedInputStream();
reader = new BufferedReader(
new InputStreamReader(pipeInput));
BufferedOutputStream out = new BufferedOutputStream(
new PipedOutputStream(pipeInput))));
//Here you will have to mock the output somehow inside your
//target object.
targetObject.setOutputStream (out);
}
#Test
public test() {
//Invoke the target method
targetObject.targetMethod();
//Check that the correct data has been written correctly in
//the output stream reading it from the plugged input stream
Assert.assertEquals("something you expects", reader.readLine());
}
I'll admit that I'm probably partial to using a ByteArrayOutputStream as the lowest level OutputStream, fetching the data after execution and peforming whatever assertions that are needed. (perhaps using SAX or other XML parser to read in the data and dive through the structure)
If you want to do this with a mock, I'll admit I'm somewhat partial to Mockito, and I think you could accomplish what you're looking to do with a custom Answer which when the user invokes writeCharacters on your mock, would simply append their argument to a Buffer, and then you can make assertions on it afterwards.
Here's what I have in my head (hand written, and haven't executed so syntax issues are to be expected :) )
public void myTest() {
final XMLStreamWriter mockWriter = Mockito.mock(XMLStreamWriter.class);
final StringBuffer buffer = new StringBuffer();
Mockito.when(mockWriter.writeCharacters(Matchers.anyString())).thenAnswer(
new Answer<Void>() {
Void answer(InvocationOnMock invocation) {
buffer.append((String)invocation.getArguments()[0]);
return null;
}
});
//... Inject the mock and do your test ...
Assert.assertEquals("Hello, world!",buffer.toString());
}
(Disclaimer: I'm the author of Moxie.)
I assume you want to do this using logic embedded in the mock so that calls that violate your expectation fail fast. Yes, this is possible - but not elegant/simple in any mocking library I know of. (In general mock libraries are good at testing the behavior of method calls in isolation/sequence, but poor at testing more complex interactions between calls over the lifecycle of the mock.) In this situation most people would build up a buffer as the other answers suggest - while it doesn't fail fast, the test code is simpler to implement/understand.
In the current version of Moxie, adding custom parameter-matching behavior on a mock means writing your own Hamcrest matcher. (JMock 2 and Mockito also let you use custom Hamcrest matchers; EasyMock lets you specify custom matchers that extend a similar IArgumentMatcher interface.)
You'll want a custom matcher that will verify that the string passed to writeCharacters forms the next part of the sequence of text you expect to be passed into that method over time, and which you can query at the end of the test to make sure it's received all of the expected input. An example test following this approach using Moxie is here:
http://code.google.com/p/moxiemocks/source/browse/trunk/src/test/java/moxietests/StackOverflow6392946Test.java
I've reproduced the code below:
import moxie.Mock;
import moxie.Moxie;
import moxie.MoxieOptions;
import moxie.MoxieRule;
import moxie.MoxieUnexpectedInvocationError;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
// Written in response to... http://stackoverflow.com/questions/6392946/
public class StackOverflow6392946Test {
private static class PiecewiseStringMatcher extends BaseMatcher<String> {
private final String toMatch;
private int pos = 0;
private PiecewiseStringMatcher(String toMatch) {
this.toMatch = toMatch;
}
public boolean matches(Object item) {
String itemAsString = (item == null) ? "" : item.toString();
if (!toMatch.substring(pos).startsWith(itemAsString)) {
return false;
}
pos += itemAsString.length();
return true;
}
public void describeTo(Description description) {
description.appendText("a series of strings which when concatenated form the string \"" + toMatch + '"');
}
public boolean hasMatchedEntirely() {
return pos == toMatch.length();
}
}
#Rule
public MoxieRule moxie = new MoxieRule();
#Mock
public XMLStreamWriter xmlStreamWriter;
// xmlStreamWriter gets invoked with strings which add up to "blah blah", so the test passes.
#Test
public void happyPathTest() throws XMLStreamException{
PiecewiseStringMatcher addsUpToBlahBlah = new PiecewiseStringMatcher("blah blah");
Moxie.expect(xmlStreamWriter).anyTimes().on().writeCharacters(Moxie.argThat(addsUpToBlahBlah));
xmlStreamWriter.writeCharacters("blah ");
xmlStreamWriter.writeCharacters("blah");
Assert.assertTrue(addsUpToBlahBlah.hasMatchedEntirely());
}
// xmlStreamWriter's parameters don't add up to "blah blah", so the test would fail without the catch clause.
// Also note that the final assert is false.
#Test
public void sadPathTest1() throws XMLStreamException{
// We've specified the deprecated IGNORE_BACKGROUND_FAILURES option as otherwise Moxie works very hard
// to ensure that unexpected invocations can't get silently swallowed (so this test will fail).
Moxie.reset(xmlStreamWriter, MoxieOptions.IGNORE_BACKGROUND_FAILURES);
PiecewiseStringMatcher addsUpToBlahBlah = new PiecewiseStringMatcher("blah blah");
Moxie.expect(xmlStreamWriter).anyTimes().on().writeCharacters(Moxie.argThat(addsUpToBlahBlah));
xmlStreamWriter.writeCharacters("blah ");
try {
xmlStreamWriter.writeCharacters("boink");
Assert.fail("above line should have thrown a MoxieUnexpectedInvocationError");
} catch (MoxieUnexpectedInvocationError e) {
// as expected
}
// In a normal test we'd assert true here.
// Here we assert false to verify that the behavior we're looking for has NOT occurred.
Assert.assertFalse(addsUpToBlahBlah.hasMatchedEntirely());
}
// xmlStreamWriter's parameters add up to "blah bl", so the mock itself doesn't fail.
// However the final assertion fails, as the matcher didn't see the entire string "blah blah".
#Test
public void sadPathTest2() throws XMLStreamException{
PiecewiseStringMatcher addsUpToBlahBlah = new PiecewiseStringMatcher("blah blah");
Moxie.expect(xmlStreamWriter).anyTimes().on().writeCharacters(Moxie.argThat(addsUpToBlahBlah));
xmlStreamWriter.writeCharacters("blah ");
xmlStreamWriter.writeCharacters("bl");
// In a normal test we'd assert true here.
// Here we assert false to verify that the behavior we're looking for has NOT occurred.
Assert.assertFalse(addsUpToBlahBlah.hasMatchedEntirely());
}
}
I'm trying to get PowerMock to work with mockito, and I'm following the documentation here: http://code.google.com/p/powermock/wiki/MockitoUsage13.
To simplify a bit, lets say that I have a static method:
StaticObj.put(String key, String val) { ... }
And the class to be tested does something like this:
public class ClassToTest {
public void doSomething(Params p) {
if (StringUtils.isNotBlank(p.getK()) StaticObj.put("k1", p.getK());
if (StringUtils.isNotBlank(p.getX()) StaticObj.put("x1", p.getX());
}
}
In my unit test I'd like to verify that StaticObj.put is called for K and X when they are not blank or null, so I do something like this:
public void testNormalCase() {
// assume that mocking setup for statics already happened in some #Before function..
Params params = new Params("k", "x");
ClassToTest classToTest = new ClassToTest();
classToTest.doSomething(params);
// now I want to verify:
PowerMockito.verifyStatic(times(1));
StaticObj.put("k1", "k1");
PowerMockito.verifyStatic(times(1));
StaticObj.put("x1", "x");
}
This works, and it's what I'd expect. What doesn't work, is if I comment out the verification for K, then the verification for X fails! The error message indicates that ("x1", "x") is expected but got ("k1", "k"). Why is this? Am I not coding this correctly?
Also it leads me to believe that the following type of test, which passes, might pass for the wrong reason entirely:
public void testOtherCase() {
// assume that mocking setup for statics already happened in some #Before function..
Params params = new Params("k", null);
ClassToTest classToTest = new ClassToTest();
classToTest.doSomething();
// now I want to verify:
PowerMockito.verifyStatic(never());
StaticObj.put(eq("x1"), anyString());
}
E.g. I wonder if powermock sees "k1", decides that "x1" was never called, and passes. (?)
To state it generally, I have a static method that is called N times (where N changes depending on the input params). And I want to verify that it was called in the correct cases (which can be determined by input params). It seems like powermock doesn't handle this well, unless I misunderstand.
Thanks for any ideas!
I read this question and the issue carefully but not sure if I understood them clearly - From my understanding, it's correct that powermock raise the exception when you pass k and x but only verify k.
Because you are mocking the static method StaticObj.put, when you pass parameter k and x and verify it with
PowerMockito.verifyStatic(times(1));
StaticObj.put("k1", "k1");
PowerMockito.verifyStatic(times(1));
StaticObj.put("x1", "x");
This should work. And when you verify parameter k and x with verification for k is commented out.
// PowerMockito.verifyStatic(times(1));
// StaticObj.put("k1", "k1");
PowerMockito.verifyStatic(times(1));
StaticObj.put("x1", "x");
Powermock will get the invocation with put("k1"...) first apparently, so the verification of x will raise an error. Your verification process is sequenced.
I don't know as of which version, but PowerMockito.verifyStatic(VerificationMode) is deprecated. Just wanted to point that out to anyone else finding this years after the last post.