Junit Parameterized Constructor - Wrong Number of Arguments - java

I am trying to build a parameterized Junit Test in order to test each occurrence of a LinkedHashMap within an ArrayList of LinkedHashMaps. This is because each LinkedHashMap represents a test case.
The map is built/stored by a object within my TestSuite class, which utilizes the #BeforeClass annotation, as per below:
#RunWith(Suite.class)
public class TestSuite {
public static MapBuilder mapBuilder = new MapBuilder ();
#ClassRule
public static ExternalResource testResource = new ExternalResource();
#Override
protected void before () throws IOException {
mapBuilder.buildMap();
}
}
The .buildMap() method of Mapbuilder is expensive, so I do not wish to build it for every Junit Test, hence the need for parameterized class, as per below :
#RunWith(Parameterized.class)
public class TestCasesA {
private LinkedHashMap<Integer, Integer> currentMap;
public TestCasesA (LinkedHashMap<Integer, Integer> currentMap) {
this.currentMap = currentMap;
}
#Parameters
public static Collection<Object[]> dataFeed () {
Object[] objArray = TestSuite.MapBuilder.returnBuiltMap().toArray();
return Arrays.asList(new Object[][] {objArray});
}
#Test
// Some test which uses currentMap
}
However, when i run this i keep facing the below issue:
java.lang.IllegalArgumentException: wrong number of arguments at java.lang.reflect.Constructor.newInstance(Unknown Source)
I've been scouring Stack Overflow and other sites about this all day, but i still cannot work it out.
Not sure if this matters or not but my LinkedHashMap may contain between 1 upto around 32 key/value entries (Could contain more, but very unlikely).
I'v followed the plentiful examples online where you manually type what you want to return, and this works fine, but manually typing in is not suitable for what i'm trying to achieve.
I've even done a enhanced for loop within TestCasesB, called the .returnBuiltMap() method and printed out each iteration of the map just to prove my Test Cases can "see" the built map.
Can anyone help?
For reference, I am using Java 7 and Junit 4.

I've been researching this further myself due to lack of any answers (Uploading the wrong code in my original post was a bad move on my part admittedly).
I finally found the answer today - #BeforeClass runs after #Parameters, as discussed in great detail here > https://github.com/junit-team/junit4/issues/527
My above code was always going fail as my data set-up was performed after #Parameters ran, so #Parameters had nothing to feed into the designated constructor.

It seems you have forgotten to add the constructor, something like:
#RunWith(Parameterized.class)
public class TestCasesA {
private Integer paramA, paramB;
#Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] {
{ 1, 1 },
{ 2, 2 }
});
}
public TestCasesA (Integer paramA, Integer paramB){
this.paramA = paramA;
this.paramB = paramB;
}
#Test
public void testYourParams() {
assertEquals(paramA, paramB);
}
}

I was also fasing this error:
java.lang.IllegalArgumentException: wrong number of arguments
after I removed paramether from constructor, but then I found that I also must delete it from #Parameterized.Parameters in
companior object. See the code below:
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
import io.mockk.spyk
import io.mockk.verify
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runBlockingTest
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
#ExperimentalCoroutinesApi
#RunWith(Parameterized::class)
class MyAppClass1UseCaseTest(
private val expectedFirstParam: String,
expectedSecondParam: Boolean //If you remove paramether from here, then you also have to remove param from copmanion // object below
) {
#Test
fun useCaseTest1() = runBlockingTest {
}
companion object {
#JvmStatic
#Parameterized.Parameters(name = "firstParam {0}, secondParam {1}") //you also need to remove param from here
fun data(): Collection<Array<Any?>> {
return listOf(
arrayOf("stringValue1", true), //and remove param from here
arrayOf("stringValue1", false)
)
}
}
}

Related

any(Classmember) returns null mockito

I am trying to do when().thenReturn() but facing issues. Following is the sample code that I came up with for SOers:
import java.util.List;
public class Sample {
public void function(List<SampleA> list) {
for (SampleA s : list) {
List<SampleB> nameList = s.v1;
for (SampleB m : nameList) {
SampleC value = m.getV2();
if (value != null) {
doSomething(value);
} else {
LOGGER.warn("No valid value");
}
}
}
}
}
public class SampleA{
List<SampleB> v1;
}
public class SampleB{
SampleC v2;
public SampleC getV2(){
return this.v2;
}
}
This might be silly but I just want to understand why can't I do:
SampleB sampleB = new SampleB();
when(sampleB.getV2()).thenReturn(any(SampleC.class));
I'm guessing that you are trying to test Sample.function and are trying to work out how to mock SampleC values. If so, then your code should probably look something like:
#Test
void testFunction() {
SampleC mockC = mock(SampleC.class);
SampleB mockB = mock(SampleB.class);
SampleA mockA = mock(SampleA.class);
when(mockB.getV2()).thenReturn(mockC);
when(mockA.getV1()).thenReturn(List.of(mockB));
Sample sample = new Sample();
sample.function(List.of(mockA));
// verify doSomething was called with mockC as its argument
when(mockB.getV2()).thenReturn(null);
sample.function(List.of(mockA));
// verify "No valid value" was logged
}
I've added a getV1 method rather than direct access to the field because my fingers refuse to write the code that directly accesses a public field :-)
If you're struggling with verifying that doSomething was called then that's where argument matching comes in. Ideally you'd have a SomethingDoer that you inject into your sample:
interface SomethingDoer {
void doSomething(SampleC sample);
}
class Sample {
private final SomethingDoer somethingDoer;
public Sample(SomethingDoer somethingDoer) {
this.somethingDoer = somethingDoer;
}
}
Then you'd add the following to your test:
SomethingDoer doer = mock(SomethingDoer.class);
Sample sample = new Sample(doer);
...
verify(doer).doSomething(mockC);
Also note that the code above is poor style: the tests should be split up with the setup code in a #BeforeEach method. I've just put it in a single test to keep the answer simple.
any(…) is an ArgumentMatcher. It is used to match arguments. You cannot use it to return instances of classes. What would "any SampleC" be?
You'd use it with mock objects, like so:
SampleInterface sample = Mockito.mock(SampleInterface.class);
when(sample.function(any(List.class))).thenReturn(new ArrayList<>());
// or: .thenAnswer(a -> new ArrayList<>()); to return a new instance for each call
you can't use ArgumentMatchers inside thenReturn or thenAnswer. You have to specify exactly what to return. For Example:
SampleB sampleB = mock(SampleB.class)
when(sampleB.getV2()).thenReturn(new SampleC());

How to resolve NoSuchMethodException in java when calling custom spark UDF

I've a java spark streaming app (using spark 3.0.1) where I need to call custom transformations on streaming data. These custom transformations are defined inside a class as methods and given to us as a jar file. We need to wrap these methods in UDFs and call those in our spark code. A sample set of transformations can be defined as follows. Please remember it comes as a jar.
import java.io.Serializable;
public class CustomTransformations implements Serializable {
public String f1(String input) {
return input + "_1";
}
public String f2(String input) {
return input + "_2";
}
public String f3(String input) {
return input + "_3";
}
}
Let's assume somewhere (e.g. json or config file) we have a map of the transformations and the corresponding method names (Strings), so that given the transformation, we can wrap the corresponding method in a UDF and invoke it. I created the following class for this purpose.
import java.lang.reflect.Method;
import static org.apache.spark.sql.functions.udf;
public class Creator {
public static UserDefinedFunction getUDF(CustomTransformations ct, String funcName)
throws NoSuchMethodException {
Method method = ct.getClass().getDeclaredMethod(funcName);
return udf(
(UDF1<String, Object>) method::invoke, DataTypes.StringType);
}
}
So far no compilation error. But now the issue is, if I call this method getUDF from the spark code, it shows a NoSuchMethodException. E.g. my spark code is something like following.
public class SampleSparkJob {
public static void main(String[] args) {
SparkSession.Builder sparkSessionBuilder = SparkSession.builder()
.master("local[2]")
.appName("sample-streaming");
CustomTransformations ct = new CustomTransformations();
try (SparkSession spark = sparkSessionBuilder.getOrCreate()) {
Dataset<Row> df1 = MyKafkaConnectors.readFromKafka();
// this is where I get the exceptions
Dataset<Row> df2 = df1
.withColumn("value", Creator.getUDF(ct, "f1").apply(col("value")))
.withColumn("value", Creator.getUDF(ct, "f2").apply(col("value")))
.withColumn("value", Creator.getUDF(ct, "f3").apply(col("value")));
StreamingQuery query = MyKafkaConnectors.WriteToKafka(df2);
query.awaitTermination();
} catch (TimeoutException | StreamingQueryException | NoSuchMethodException e) {
e.printStackTrace();
}
}
}
This is the error that I get:
java.lang.NoSuchMethodException: <pkgname>.CustomTransformations.f1()
at java.base/java.lang.Class.getDeclaredMethod(Class.java:2475)
at Creator.getUDF(Creator.java:14)
at SampleSparkJob.main(SampleSparkJob.java:29)
The package-name is correct. Clearly, the client's CustomTransformations class has a method f1. So I'm not able to understand why it's showing this error. Any help is appreciated.
Your code has two problems, both unrelated to spark.
First, NoSuchMethodException:CustomTransformations.f1() is telling you that no method f1 without any parameters does exist. This is true.
You need to specify parameter types to getDeclaredMethod (String in this case).
Second, a method cannot be called on his own with invoke, you need to pass the "owner" or "this" object to invoke.
Then Creator fixed looks like this:
public class Creator {
public static UserDefinedFunction getUDF(CustomTransformations ct, String funcName)
throws NoSuchMethodException {
Method method = ct.getClass().getDeclaredMethod(funcName, String.class);
return udf(
(UDF1<String, Object>) (s -> method.invoke(ct, s)), DataTypes.StringType);
}
}
And it will work just fine.
I've only one point to add to the precise answer given by #fonkap. As the java.lang.reflect.Method is not serializable, we need to bypass referencing that object in our getUDF method. The Creator class will be something like the following.
import static org.apache.spark.sql.functions.udf;
public class Creator implements Serializable {
public static UserDefinedFunction getUDF(CustomTransformation ct, String funcName) {
return udf((UDF1<String, Object>) (s -> ct.getClass().getDeclaredMethod(funcName,
String.class).invoke(ct, s)),
DataTypes.StringType);
}
}

Mock a constructor with parameter

I have a class as below:
public class A {
public A(String test) {
bla bla bla
}
public String check() {
bla bla bla
}
}
The logic in the constructor A(String test) and check() are the things I am trying to mock. I want any calls like: new A($$$any string$$$).check() returns a dummy string "test".
I tried:
A a = mock(A.class);
when(a.check()).thenReturn("test");
String test = a.check(); // to this point, everything works. test shows as "tests"
whenNew(A.class).withArguments(Matchers.anyString()).thenReturn(rk);
// also tried:
//whenNew(A.class).withParameterTypes(String.class).withArguments(Matchers.anyString()).thenReturn(rk);
new A("random string").check(); // this doesn't work
But it doesn't seem to be working. new A($$$any string$$$).check() is still going through the constructor logic instead of fetch the mocked object of A.
The code you posted works for me with the latest version of Mockito and Powermockito. Maybe you haven't prepared A?
Try this:
A.java
public class A {
private final String test;
public A(String test) {
this.test = test;
}
public String check() {
return "checked " + this.test;
}
}
MockA.java
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(A.class)
public class MockA {
#Test
public void test_not_mocked() throws Throwable {
assertThat(new A("random string").check(), equalTo("checked random string"));
}
#Test
public void test_mocked() throws Throwable {
A a = mock(A.class);
when(a.check()).thenReturn("test");
PowerMockito.whenNew(A.class).withArguments(Mockito.anyString()).thenReturn(a);
assertThat(new A("random string").check(), equalTo("test"));
}
}
Both tests should pass with mockito 1.9.0, powermockito 1.4.12 and junit 4.8.2
To my knowledge, you can't mock constructors with mockito, only methods. But according to the wiki on the Mockito google code page there is a way to mock the constructor behavior by creating a method in your class which return a new instance of that class. then you can mock out that method. Below is an excerpt directly from the Mockito wiki:
Pattern 1 - using one-line methods for object creation
To use pattern 1 (testing a class called MyClass), you would replace a call like
Foo foo = new Foo( a, b, c );
with
Foo foo = makeFoo( a, b, c );
and write a one-line method
Foo makeFoo( A a, B b, C c ) {
return new Foo( a, b, c );
}
It's important that you don't include any logic in the method; just the one line that creates the
object. The reason for this is that the method itself is never going
to be unit tested.
When you come to test the class, the object that you test will
actually be a Mockito spy, with this method overridden, to return a
mock. What you're testing is therefore not the class itself, but a
very slightly modified version of it.
Your test class might contain members like
#Mock private Foo mockFoo;
private MyClass toTest = spy(new MyClass());
Lastly, inside your test method you mock out the call to
makeFoo with a line like
doReturn( mockFoo )
.when( toTest )
.makeFoo( any( A.class ), any( B.class ), any( C.class ));
You can use matchers that are more specific than any() if you want to
check the arguments that are passed to the constructor.
If you're just wanting to return a mocked object of your class I think this should work for you. In any case you can read more about mocking object creation here:
http://code.google.com/p/mockito/wiki/MockingObjectCreation
With Mockito you can use withSettings(). For example if the CounterService required 2 dependencies, you can pass them as a mock:
UserService userService = Mockito.mock(UserService.class);
SearchService searchService = Mockito.mock(SearchService.class);
CounterService counterService = Mockito.mock(CounterService.class, withSettings().useConstructor(userService, searchService));
Starting with version 3.5.0 of Mockito and using the InlineMockMaker, you can now mock object constructions:
try (MockedConstruction mocked = mockConstruction(A.class)) {
A a = new A();
when(a.check()).thenReturn("bar");
}
Inside the try-with-resources construct all object constructions are returning a mock.
Without Using Powermock .... See the example below based on Ben Glasser answer since it took me some time to figure it out ..hope that saves some times ...
Original Class :
public class AClazz {
public void updateObject(CClazz cClazzObj) {
log.debug("Bundler set.");
cClazzObj.setBundler(new BClazz(cClazzObj, 10));
}
}
Modified Class :
#Slf4j
public class AClazz {
public void updateObject(CClazz cClazzObj) {
log.debug("Bundler set.");
cClazzObj.setBundler(getBObject(cClazzObj, 10));
}
protected BClazz getBObject(CClazz cClazzObj, int i) {
return new BClazz(cClazzObj, 10);
}
}
Test Class
public class AClazzTest {
#InjectMocks
#Spy
private AClazz aClazzObj;
#Mock
private CClazz cClazzObj;
#Mock
private BClazz bClassObj;
#Before
public void setUp() throws Exception {
Mockito.doReturn(bClassObj)
.when(aClazzObj)
.getBObject(Mockito.eq(cClazzObj), Mockito.anyInt());
}
#Test
public void testConfigStrategy() {
aClazzObj.updateObject(cClazzObj);
Mockito.verify(cClazzObj, Mockito.times(1)).setBundler(bClassObj);
}
}
Mockito has limitations testing final, static, and private methods.
Alternate Solution:
with jMockit testing library, you can do few stuff very easy and straight-forward as below:
Mock constructor of a java.io.File class:
new MockUp<File>(){
#Mock
public void $init(String pathname){
System.out.println(pathname);
// or do whatever you want
}
};
the public constructor name should be replaced with $init
arguments and exceptions thrown remains same
return type should be defined as void
Mock a static method:
remove static from the method mock signature
method signature remains same otherwise
Using Mockito 4 (but I suspect this is true for Mockito from 3.5.0 version) you can mock the constructor and, in the initializer, you can assert the values of the parameters.
For example:
try (MockedConstruction<A> constr = mockConstruction(A.class,
(mock, context) -> {
if (context.getCount() == 1) {
assertArrayEquals(context.arguments().toArray(), new Object[] {"test"});
} else {
fail("No more calls should happen");
}
})) {
// Do the rest of assertions.
}
Notice that you need to put the MockedConstruction instantiation in a try-with-resources otherwise the mocked construction is leaked outside the test.

Reset class static variable during unit test

I am trying to write a unit test for a legacy code. The class which I'm testing has several static variables. My test case class has a few #Test methods. Hence all of them share the same state.
Is there way to reset all static variables between tests?
One solution I came up is to explicitly reset each field, e.g.:
field(MyUnit.class, "staticString").set(null, null);
((Map) field(MyUnit.class, "staticFinalHashMap").get(null)).clear();
As you see, each variable needs custom re-initialization. The approach is not easy to scale, there are a lot such classes in the legacy code base. Is there any way to reset everything at once? Maybe by reloading the class each time?
As a possible good solution I think is to use something like powermock and create a separate classloader for each test. But I don't see easy way to do it.
Ok, I think I figured it out. It is very simple.
It is possible to move #PrepareForTest powermock's annotation to the method level. In this case powermock creates classloader per method. So it does that I need.
Let's say I'm testing some code involving this class:
import java.math.BigInteger;
import java.util.HashSet;
public class MyClass {
static int someStaticField = 5;
static BigInteger anotherStaticField = BigInteger.ONE;
static HashSet<Integer> mutableStaticField = new HashSet<Integer>();
}
You can reset all of the static fields programmatically using Java's reflection capabilities. You will need to store all of the initial values before you begin the test, and then you'll need to reset those values before each test is run. JUnit has #BeforeClass and #Before annotations that work nicely for this. Here's a simple example:
import static org.junit.Assert.*;
import java.lang.reflect.Field;
import java.math.BigInteger;
import java.util.Map;
import java.util.HashMap;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
public class MyTest extends Object {
static Class<?> staticClass = MyClass.class;
static Map<Field,Object> defaultFieldVals = new HashMap<Field,Object>();
static Object tryClone(Object v) throws Exception {
if (v instanceof Cloneable) {
return v.getClass().getMethod("clone").invoke(v);
}
return v;
}
#BeforeClass
public static void setUpBeforeClass() throws Exception {
Field[] allFields = staticClass.getDeclaredFields();
try {
for (Field field : allFields) {
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
Object value = tryClone(field.get(null));
defaultFieldVals.put(field, value);
}
}
}
catch (IllegalAccessException e) {
System.err.println(e);
System.exit(1);
}
}
#AfterClass
public static void tearDownAfterClass() {
defaultFieldVals = null;
}
#Before
public void setUp() throws Exception {
// Reset all static fields
for (Map.Entry<Field, Object> entry : defaultFieldVals.entrySet()) {
Field field = entry.getKey();
Object value = entry.getValue();
Class<?> type = field.getType();
// Primitive types
if (type == Integer.TYPE) {
field.setInt(null, (Integer) value);
}
// ... all other primitive types need to be handled similarly
// All object types
else {
field.set(null, tryClone(value));
}
}
}
private void testBody() {
assertTrue(MyClass.someStaticField == 5);
assertTrue(MyClass.anotherStaticField == BigInteger.ONE);
assertTrue(MyClass.mutableStaticField.isEmpty());
MyClass.someStaticField++;
MyClass.anotherStaticField = BigInteger.TEN;
MyClass.mutableStaticField.add(1);
assertTrue(MyClass.someStaticField == 6);
assertTrue(MyClass.anotherStaticField.equals(BigInteger.TEN));
assertTrue(MyClass.mutableStaticField.contains(1));
}
#Test
public void test1() {
testBody();
}
#Test
public void test2() {
testBody();
}
}
As I noted in the comments in setUp(), you'll need to handle the rest of the primitive types with similar code for that to handle ints. All of the wrapper classes have a TYPE field (e.g. Double.TYPE and Character.TYPE) which you can check just like Integer.TYPE. If the field's type isn't one of the primitive types (including primitive arrays) then it's an Object and can be handled as a generic Object.
The code might need to be tweaked to handle final, private, and protected fields, but you should be able to figure how to do that from the documentation.
Good luck with your legacy code!
Edit:
I forgot to mention, if the initial value stored in one of the static fields is mutated then simply caching it and restoring it won't do the trick since it will just re-assign the mutated object. I'm also assuming that you'll be able to expand on this code to work with an array of static classes rather than a single class.
Edit:
I've added a check for Cloneable objects to handle cases like the HashMap in your example. Obviously it's not perfect, but hopefully this will cover most of the cases you'll run in to. Hopefully there are few enough edge cases that it won't be too big of a pain to reset them by hand (i.e. add the reset code to the setUp() method).
Here's my two cents
1. Extract static reference into getters / setters
This works when you are able to create a subclass of it.
public class LegacyCode {
private static Map<String, Object> something = new HashMap<String, Object>();
public void doSomethingWithMap() {
Object a = something.get("Object")
...
// do something with a
...
something.put("Object", a);
}
}
change into
public class LegacyCode {
private static Map<String, Object> something = new HashMap<String, Object>();
public void doSomethingWithMap() {
Object a = getFromMap("Object");
...
// do something with a
...
setMap("Object", a);
}
protected Object getFromMap(String key) {
return something.get(key);
}
protected void setMap(String key, Object value) {
seomthing.put(key, value);
}
}
then you can get rid of dependency by subclass it.
public class TestableLegacyCode extends LegacyCode {
private Map<String, Object> map = new HashMap<String, Object>();
protected Object getFromMap(String key) {
return map.get(key);
}
protected void setMap(String key, Object value) {
map.put(key, value);
}
}
2. Introduce static setter
This one should be pretty obvious.
public class LegacyCode {
private static Map<String, Object> something = new HashMap<String, Object>();
public static setSomethingForTesting(Map<String, Object> somethingForTest) {
something = somethingForTest;
}
....
}
Both ways are not pretty, but we can always come back later once we have tests.

How to tell a Mockito mock object to return something different the next time it is called?

So, I'm creating a mock object as a static variable on the class level like so... In one test, I want Foo.someMethod() to return a certain value, while in another test, I want it to return a different value. The problem I'm having is that it seems I need to rebuild the mocks to get this to work correctly. I'd like to avoid rebuilding the mocks, and just use the same objects in each test.
class TestClass {
private static Foo mockFoo;
#BeforeClass
public static void setUp() {
mockFoo = mock(Foo.class);
}
#Test
public void test1() {
when(mockFoo.someMethod()).thenReturn(0);
TestObject testObj = new TestObject(mockFoo);
testObj.bar(); // calls mockFoo.someMethod(), receiving 0 as the value
}
#Test
public void test2() {
when(mockFoo.someMethod()).thenReturn(1);
TestObject testObj = new TestObject(mockFoo);
testObj.bar(); // calls mockFoo.someMethod(), STILL receiving 0 as the value, instead of expected 1.
}
}
In the second test, I'm still receiving 0 as the value when testObj.bar() is called... What is the best way to resolve this? Note that I know I could use a different mock of Foo in each test, however, I have to chain multiple requests off of mockFoo, meaning I'd have to do the chaining in each test.
You could also Stub Consecutive Calls (#10 in 2.8.9 api). In this case, you would use multiple thenReturn calls or one thenReturn call with multiple parameters (varargs).
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.junit.Before;
import org.junit.Test;
public class TestClass {
private Foo mockFoo;
#Before
public void setup() {
setupFoo();
}
#Test
public void testFoo() {
TestObject testObj = new TestObject(mockFoo);
assertEquals(0, testObj.bar());
assertEquals(1, testObj.bar());
assertEquals(-1, testObj.bar());
assertEquals(-1, testObj.bar());
}
private void setupFoo() {
mockFoo = mock(Foo.class);
when(mockFoo.someMethod())
.thenReturn(0)
.thenReturn(1)
.thenReturn(-1); //any subsequent call will return -1
// Or a bit shorter with varargs:
when(mockFoo.someMethod())
.thenReturn(0, 1, -1); //any subsequent call will return -1
}
}
For all who search to return something and then for another call throw exception:
when(mockFoo.someMethod())
.thenReturn(obj1)
.thenReturn(obj2)
.thenThrow(new RuntimeException("Fail"));
or
when(mockFoo.someMethod())
.thenReturn(obj1, obj2)
.thenThrow(new RuntimeException("Fail"));
First of all don't make the mock static. Make it a private field. Just put your setUp class in the #Before not #BeforeClass. It might be run a bunch, but it's cheap.
Secondly, the way you have it right now is the correct way to get a mock to return something different depending on the test.
Or, even cleaner:
when(mockFoo.someMethod()).thenReturn(obj1, obj2);
For Anyone using spy() and the doReturn() instead of the when() method:
what you need to return different object on different calls is this:
doReturn(obj1).doReturn(obj2).when(this.spyFoo).someMethod();
.
For classic mocks:
when(this.mockFoo.someMethod()).thenReturn(obj1, obj2);
or with an exception being thrown:
when(mockFoo.someMethod())
.thenReturn(obj1)
.thenThrow(new IllegalArgumentException())
.thenReturn(obj2, obj3);

Categories

Resources