In Mockito, is there a way to verify that there are no more interactions on any mock I have created?
For example:
public void test()
{
...
TestObject obj = mock(TestObject);
myClass.test();
verifyNoMoreInteractionsWithMocks(); <-------
}
Is there such a method?
Since verifyNoMoreInteractions take an array of object we have to find a way to get all the created mocks.
You can create this class
public class MocksCollector {
private final List<Object> createdMocks;
public MocksCollector() {
createdMocks = new LinkedList<Object>();
final MockingProgress progress = new ThreadSafeMockingProgress();
progress.setListener(new CollectCreatedMocks(createdMocks));
}
public Object[] getMocks() {
return createdMocks.toArray();
}
}
and then use it in your test :
public class ATest {
private final MocksCollector mocksCollector = new MocksCollector();
#Test
public void test() throws Exception {
A a1 = mock(A.class);
A a2 = mock(A.class);
A a3 = mock(A.class);
assertEquals("wrong amount of mocks", 3, mocksCollector.getMocks().length);
verifyNoMoreInteractions(mocksCollector.getMocks());
a3.doSomething();
verifyNoMoreInteractions(mocksCollector.getMocks()); // fail
}
}
or with annotations :
#RunWith(MockitoJUnitRunner.class)
public class A2Test {
private final MocksCollector mocksCollector = new MocksCollector();
#Mock
private A a1;
#Mock
private A a2;
#Mock
private A a3;
#Test
public void test() throws Exception {
assertEquals("wrong amount of mocks", 3, mocksCollector.getMocks().length);
verifyNoMoreInteractions(mocksCollector.getMocks());
a2.doSomething();
verifyNoMoreInteractions(mocksCollector.getMocks()); // fail
}
}
It works but it adds a dependency on mockito internal.
Related
I have a class that I cover with tests, I am having difficulties, how can I check that inside a method addBeginList(), the operation "list.add (int)" occurs on a specific list. Using the MoŃkito library, check that a specific method was called on a list in a class?
public class ClassA implements IClassA {
private List<Integer> list;
public ClassA (List<Integer> list) {
this.list = list;
}
#Override
public int addBeginList() {
long t1 = System.currentTimeMillis();
list.add(5);
long t2 = System.currentTimeMillis();
return (int) t2 - (int) t1;
}
Test class
#RunWith(MockitoJUnitRunner.class)
public class ClassATest{
private ClassA mockClassA;
private static final int EXPECTED = 0;
private static final int DELTA = 1000;
private static final int SIZE = 7000;
#Before
public void setUp() throws Exception {
mockClassA = Mockito.mock(ClassA.class);
mockClassA.initialize(SIZE);
mockClassA.addBeginList();
}
#Test
public void initialize() {
}
#Test
public void addBeginList() {
assertEquals(EXPECTED, mockClassA.addBeginList(), DELTA);
}
First step is to make sure to test the real instance of the ClassA, not a mock.
Next you can either supply to it a real list and check that it contains a certain element after, or you supply it with a mocked list and check with Mockito that specific method was called:
verify(mockedList).add(5)
I found a solution to my problem:
public class ClassA extends AbstractList<Integer> implements IClassA {///}
In test class:
private List<Integer> mockedList;
private ClassA classA;
#Before
public void setUp() throws Exception {
mockedList = Mockito.mock(ClassA.class);
classA = new ClassA(mockedList);
}
#Test
public void addBeginList() {
assertEquals(EXPECTED, classA.addBeginList(), DELTA);
verify(mockedList).add(5);
}
I have the following class (Condensed it to focus on issue instead of showing entire class):
#Component
public class ABCDEF {
private final Helper helper;
private final URI uri;
public ABCDEF(Helper helper, #Value("${endpoint.url}") URI uri) {
this.helper = helper;
this.uri = uri;
}
public void b(){
helper.toString();
}
}
For its test, I am looking to inject the mocks as follows but it is not working.
The helper comes up as null and I end up having to add a default constructor to be able to throw the URI exception.
Please advice a way around this to be able to properly inject the mocks. Thanks.
#RunWith(JUnitMockitoRunner.class)
public class ABCDEFTest {
#Mock
private Helper helper;
#InjectMocks
private ABCDEF abcdef = new ABCDEF(
helper,
new URI("test")
);
// adding just to be able to throw Exception
public ABCDEFTest() throws URISyntaxException {
}
#Test
public void b() {
abcdef.b();
}
}
Note: Using Mockito version 1.10.19. Will need to stick to this version.
This should work:
#RunWith(MockitoJUnitRunner.class)
public class ABCDEFTest {
#Mock
private Helper helper;
private ABCDEF abcdef;
#Before
public void setUp() throws URISyntaxException {
abcdef = new ABCDEF(
helper,
new URI("test")
);
}
#Test
public void b() {
abcdef.b();
}
}
Or, instead of using #RunWith, you can initialize mock inside setUp method:
public class ABCDEFTest {
private Helper helper;
private ABCDEF abcdef;
#Before
public void setUp() throws URISyntaxException {
helper = Mockito.mock(Helper.class);
abcdef = new ABCDEF(
helper,
new URI("test")
);
}
#Test
public void b() {
abcdef.b();
}
}
Testing class
stream list into map, where I get atribute from an element of this list
public class MyClass {
private final Map<String, IMyInterface> map;
public MyClass(final List<IMyInterface> list) {
this.map = list.stream().collect(Collectors.toMap(IMyInterface::getUniqueName, i -> i));
}
}
Test
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
#InjectMock
private MyClass instance;
#Spy
private ArrayList<IMyInterface> list;
#Mock
private A a;
#Mock
private B b;
#Before void setUp() throws Exception {
list.add(a);
list.add(b);
}
}
Or Test
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
#Spy
private ArrayList<IMyInterface> list;
#Mock
private A a;
#Mock
private B b;
private class MockedClass extends MyClass {
MockedClass(List<IMyInterface> list) {
super(list);
}
}
#Before void setUp() throws Exception {
list.add(a);
list.add(b);
}
}
How to get injected Map after execute constructor? I have to test this class and use map object
EDIT:
IMyInterface::getUniqueName()
is a method in interface
objects A and B implements IMyInterface
I want to collect injected list into map
When I add elements into list, I got it in debugging mode in my tested class, but when debugging mode is on
list.stream().collect(Collectors.toMap(IMyInterface::getUniqueName(), i -> i));
it stop
The correct answer is that should I mock A and B in my #Before
private A a;
private B b;
#Before
public void setUp() throws Exception {
a = new A(mock.Service.class); // cause it have an argument
b = new B(mock.Service.class); // cause it have an argument
list.add(a);
list.add(b);
}
I have a class to be tested which is like this:
public class MainClass extends BaseClass {
public static int variableToBeAsserted= 0;
MainClass(ConfigClass config) {
super(config);
}
public void myMethod() {
List list = objectOfClass1inSuperClass.operation(objectOfClass2inSuperClass.method())
while(methodInSuperClass()) {
// doing operations with 'list'
variableToBeAsserted++;
}
}
// ..few other methods which I am not going to test.
}
I have suppressed the constructor of my BaseClass and my ConfigClass. Now my test class is like this:
#RunWith(PowerMockRunner.class)
#PrepareForTest(MainClass.class)
public class TestClass {
#Before
public void setUp(){
suppress(constructor(BaseClass.class))
suppress(constructor(ConfigClass.class))
}
#Test
public void testMyMethod(){
MainClass main = new MainClass(new ConfigClass(""));
List list1= new ArrayList();
test1.add("somevalues");
Class1inSuperClass ob1 = PowerMock.createMock(Class1inSuperClass.class);
Class2inSuperClass ob2 = PowerMock.createMock(Class2inSuperClass.class);
EasyMock.expect(ob2.method()).andReturn(getClass());
EasyMock.expect(ob1.operation(getClass())).andReturn(list1);
PowerMock.replayAll();
main.myMethod();
Assert.assertEquals(expectedValue, main.variableToBeAsserted);
}
}
Now I don't know why but my test case fails with a NullPointerException.
It tries to access objectofClass1inSuperClass and fails. I thought this will mock it. But it does not get mocked.
EDIT: I am writing only the test and I cannot change anything in BaseClass. However I have the option to modify the MainClass.
You have two ways to inject mock object to the object under the test.
Manually via WhiteBox
#RunWith(PowerMockRunner.class)
#PrepareForTest(MainClass.class)
public class WhiteBoxApproachTestClass {
#Before
public void setUp() throws Exception {
suppress(constructor(BaseClass.class));
}
#Test
public void testMyMethod() {
MainClass main = new MainClass(createMock(ConfigClass.class));
List<String> list1 = new ArrayList<>();
list1.add("somevalues");
Class1inSuperClass ob1 = createMock(Class1inSuperClass.class);
Class2inSuperClass ob2 = createMock(Class2inSuperClass.class);
expect(ob2.method()).andReturn(getClass());
expect(ob1.operation(getClass())).andReturn(list1);
Whitebox.setInternalState(main, "objectOfClass1inSuperClass", ob1);
Whitebox.setInternalState(main, "objectOfClass2inSuperClass", ob2);
replayAll();
main.myMethod();
assertThat(MainClass.variableToBeAsserted).isEqualTo(5);
}
}
And via #TestSubject (http://easymock.org/user-guide.html#mocking-annotations)
#RunWith(PowerMockRunner.class)
#PrepareForTest(MainClass.class)
public class TestSubjectApproachTestClass {
#Mock(fieldName = "objectOfClass1inSuperClass")
private Class1inSuperClass ob1;
#Mock(fieldName = "objectOfClass2inSuperClass")
private Class2inSuperClass ob2;
#TestSubject
private final MainClass main = new MainClass(createMock(ConfigClass.class));
#BeforeClass
public static void before() throws Exception {
suppress(constructor(BaseClass.class));
}
#Test
public void testMyMethod() {
List<String> list1= new ArrayList<>();
list1.add("somevalues");
expect(ob2.method()).andReturn(getClass());
expect(ob1.operation(getClass())).andReturn(list1);
EasyMockSupport.injectMocks(main);
replayAll();
main.myMethod();
assertThat(MainClass.variableToBeAsserted).isEqualTo(5);
}
}
Full code you may find here.
Lets assume the following JUnit test class:
#RunWith(Parameterized.class)
public class MyTestClass {
private ExpensiveObjectToCreate myObject;
#Parameters
public static Collection<Object[]> data() {
Object[][] data = new Object[][] {
{ "parameter1" },
{ "parameter2" },
};
return Arrays.asList(data);
}
#Test
public void test1() {
}
#Test
public void test2() {
}
public MyTestClass(String stringParameter) {
myObject = new ExpensiveObjectToCreate(stringParameter);
}
}
Is there any way for me to create the expensive object just once for every parameter set? I say this because JUnit creates a new test class for every test it needs to run. This means that the expensive object is NOT created 2 times, but actually 4 times (2 parameter sets x 2 tests). This gets even worse when we have many test methods.
Also, sending the expensive object as a parameter is not a solution for me because my scenario is a little bit more complicated (I create the expensive object in JUnit rules).
Why not just roll out a custom cacher in your test case class, which caches the instance created per parameter and returns the same instance on further invocations.
#RunWith(Parameterized.class)
public class Test {
private static ExpensiveObjectCacher cacher; //instance which caches parameter instance
private ExpensiveObject myObject;
public Test(String value) {
this.myObject = cacher.get(value);
}
#BeforeClass
public static void setUpBeforeClass(){
cacher = new ExpensiveObjectCacher();
}
#Parameters
public static Collection<Object[]> data() {
Object[][] data = new Object[][] {
{ "parameter1" },
{ "parameter2" },
};
return Arrays.asList(data);
}
#org.junit.Test
public void test1(){
}
#org.junit.Test
public void test2(){
}
}
//caching for test cases.
class ExpensiveObjectCacher{
private Map<String, ExpensiveObject> map = new ConcurrentHashMap<String, ExpensiveObject>();
ExpensiveObject get(String value){
ExpensiveObject instance = map.get(value);
if(instance == null){
instance = new ExpensiveObject(value);
map.put(value, instance);
}
return instance;
}
}
class ExpensiveObject{
public ExpensiveObject(String value) {
System.out.println("Instance created: " + value);
}
}
Output:
Instance created: parameter1
Instance created: parameter2
You could work with a static Map from the parameters (here a simple string) to instances of ExpensiveObjectToCreate.
#RunWith(Parameterized.class)
public fnial class MyTestClass {
private static final Map<Parameter, ExpensiveObjectToCreate> MAPPING = new HashMap<>();
private ExpensiveObjectToCreate myEOTC;
public MyTestClass(String stringParameter) {
myEOTC = getEOTC(new Parameter(stringParameter));
}
private static getEOTC(Parameter parameter) {
ExpensiveObjectToCreate eotc = MAPPING.get(parameter);
if (eotc == null) {
eotc = new ExpensiveObjectToCreate(parameter.stringParameter);
MAPPING.put(parameter, eotc);
}
rturn eotc;
}
private static final class Parameter {
String stringParameter;
Parameter(String stringParameter) { this.stringParameter = stringParameter; }
#Override public int hashCode() { ... }
#Override public boolean equals(Object other) { ... }
}
}
However, if you also need to limit the number of expensive objects, you should do more work, for example a cache could be a solution.
If you're using Junit 4:
private static ExpensiveObjectToCreate myObject;
private static String stringParameter = "some text";
#BeforeClass
public static void setUpBeforeClass() throws Exception {
myObject = new ExpensiveObjectToCreate(stringParameter);
}
If Junit 3:
private static ExpensiveObjectToCreate myObject;
private static String stringParameter = "some text";
#BeforeClass
protected static void setUpBeforeClass() throws Exception {
myObject = new ExpensiveObjectToCreate(stringParameter);
}
In both cases the object will be created once for all the unit tests.
Edit: The String I am not sure where it came from, so I am asuming that the String is the same for all unit tests.