vaughanj
vaughanj

Reputation: 203

Mockito's ArgumentCaptor: One method name, two method definitions (Part 2)

I asked a similar question yesterday in which I'm using a single method name, but have two different arguments I'm passing along. This one does not involve argument types that share a parent class.

I am using PowerMockito to return a PrintWrite from a constructor. I need to mock its print methods.

There are four kinds of print/println calls I am tracking:

print(long l)
print(java.lang.String s) 
print(char c)
println()

Particularly what I care about is the one that prints a long. I have the following setup:

Mockito.doNothing().when(fakePrintWriter).println();
Mockito.doNothing().when(fakePrintWriter).print(any(Long.class));
Mockito.doNothing().when(fakePrintWriter).print(any(String.class));
Mockito.doNothing().when(fakePrintWriter).print(any(Character.class));

With the following verifies, which I want to capture certain arguments with:

Mockito.verify(fakePrintWriter, Mockito.times(11)).print(outputCaptor.capture());
Mockito.verify(fakePrintWriter, Mockito.times(1)).print(longPrintCaptor.capture());
Mockito.verify(fakePrintWriter, Mockito.times(9)).print(eq(','));
Mockito.verify(fakePrintWriter, Mockito.times(3)).println();

Which slaps me in the face with this:

Wanted but not invoked:
printWriter.print(<Capturing argument>);

Drilling down by testing a print on a long normally, I discovered that calling print(long l) is actually calling println. So, I instead changed my long print setup/verify to this:

Mockito.doNothing().when(fakePrintWriter).println(any(Long.class));
...
Mockito.verify(fakePrintWriter, Mockito.times(1)).println(longPrintCaptor.capture());

Which then gives me the resulting conflict with println:

Argument(s) are different! Wanted:
printWriter.println(<Capturing argument>);
...
Actual invocation has different arguments:
printWriter.println();
...

Expected :printWriter.println(<Capturing argument>);
Actual   :printWriter.println();

Like yesterday I am at a loss as to how to resolve this- I considered using a custom Answer to track the string that gets outputted (I want to verify the actual order of the values that are being outputted) but I believe doing so would only result in similar errors. Any ideas on what to do?

Upvotes: 2

Views: 1047

Answers (2)

Thomas
Thomas

Reputation: 301

I've tried the ByteArrayOutputStream approach and it seems to be empty when I run bytes.toString(). I've found the following seems to work if you don't mind allowing implementations in your test:

StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
...
assertThat(printWriter.getBuffer().toString()).isEqualTo(expectedOutput);

Upvotes: 0

bowmore
bowmore

Reputation: 11308

Instead of trying to mock the PrintWriter, simply use a real one, that writes to memory, instead of to a File.

ByteArrayOutputStream bytes = new ByteArrayOutputStream();
PrintWriter fakePrintWriter = new PrintWriter(byteArrayOutputStream);

// invoke method on unit under test

assertThat(bytes.toString()).isEqualTo(expectedOutput);

Upvotes: 1

Related Questions