I have the following classes:
#Getter //lombok
#AllArgsConstructor //lombok
public class A {
private Set<B> bSet;
public void aMethod() {
for (B b: bSet) b.bMethod();
}
}
#AllArgsConstructor //lombok
public class B {
public void bMethod() {
//do something
}
}
I would like to write a test that checks if bMethod() got called for every element of bSet without caring about the Implementation of bMethod(). A unit test.
This is my JUnit test case that needs to succeed:
#Test
public void givenAWithBSet_whenAMethodIsCalled_thenCallBMethodOnAllBs() {
//GIVEN a with bSet
Set<B> bSet = new HashSet<>();
bSet.add(new B());
bSet.add(new B());
A a = new A(bSet);
//WHEN aMethodIsCalled
a.aMethod();
//then call bMethod on all bs
bSet.forEach(b -> verify(b, times(1)).bMethod());
bSet.forEach(Mockito::verifyNoMoreInteractions);
}
I tried mocking it, but was unsuccessful and need your help
If you want to just verify that each B in your Set has its bMethod invoked, you can set up your test something like this:
#Test
public void givenAWithBSet_whenAMethodIsCalled_thenCallBMethodOnAllBs() {
Set<B> bSet = new HashSet<>();
for (int i = 0; i<10; i++) {
bSet.add(Mockito.mock(B.class));
}
A a = new A(bSet);
a.aMethod();
for (B b : a.getBSet()) {
verify(b).bMethod();
}
}
It will verify that bMethod was called on each of the mocks. It'd be nice to use the same mock, but as you're using a Set and the mock uses the identity function for equality, you'll need to create multiples.
Related
class Foo {
ReturnParameters function1(int a, int b) {
function2(a, b);
}
ReturnParameters function2(int a , int b) {
// body of this function...
}
}
I am creating a Junit test with Mockito and only want to test function1() and want to mock the returns from function2()
Below is my TestCase Class
class FooTest{
Foo foo = mock(Foo.class);
#Test
public void function1test(){
Mockito.when(foo.function2(1,2)).thenReturn(new ReturnParameters(100));
ReturnParameters actualResult = foo.function1(1,2);
int expectedResult = 100;
AssertEquals(expectedResult , actualResult.getStatus());
}
}
I am getting this error message that actualResult is a null value.
Can you please help?
You are attempting to partially stub the methods in a class.
In order to do this, you must use Spy instead of Mock.
Here is some sample code (that assumes you are using Junit5 and uses doReturn.when instead of when.thenReturn):
#ExtendWith(MockitoExtension.class)
class TestFoo
{
#Spy
private Foo spyClassToTest;
#BeforeEach
public void before()
{
// stub the function 2 call. The function 1 call is still "live"
doReturn(new ReturnParameters(100)).when(spyClassToTest).function2(1, 2);
}
#Test
public void function1_descriptionOfTheTestScenario_returns100()
{
ReturnParameters actualResult;
int expectedResult = 100;
// Perform the test
actualResult = spyClassToTest.function1(1, 2);
assertNotNull(actualResult);
assertEquals(expectedResult, actualResult.getStatus());
}
}
I don't know the domain but maybe its a good idea to split your functions into different classes. It should solve this issue in a clean way. Spy should also work though.
MyCode:
class LocalClass{
public getNumber(){
retunr 5;
}
}
class AnotherLocalClass{
public static getNumber(){
retunr 10;
}
}
public class A{
public int methodAa(Boolean flag, int paramValue){
return methodA(flag, paramValue);
}
private int methodA(Boolean flag, int paramValue){
int returnValue = 0;
try{
if(flag){
LocalClass localVariable = new LocalClass();
returnValue = localVariable.getNumber() + paramValue;
} else{
returnValue = AnotherLocalClass.getNumber() + paramValue;
}
return returnValue;
}catch(Exception e){
e.printStackTrace();
return 0;
}
}
}
public class ATest{
#InjectMocks
A a;
public void methodATest(){
//need help to write here
}
}
LocalClass and AnotherLocalClass are classes that contains a method that returns a value.
getNumber in AnotherLocalClass is a static method.
Class A is the main class for which I am writing ATest class.
I can only write code in methodATest. And cannot change anything in LocalClass, AnotherLocalClass or class A.
I want to write methodATest such that methodA throws an exception.
My mockito version is 1.19.10 and it cannot be changed.
And also I cannot use PowerMockito or any other new dependency.
What exceptions do you expected to occur on your code? Which parameter values will cause the exceptions? In those cases, what is the return value that you're expecting?
When you get the answers for those questions, then you gonna have to set the conditions for the exception to happen. Then your code is gonna look something like this:
public class ATest{
A a = new A();
#Test
public void methodATest(){
Boolean flag = ?;
int paramValue = ?;
int expectedReturnValue = ?;
int returnValue = a.methodAa(flag, paramValue);
assertEquals(expectedReturnValue, returnValue);
}
}
Look out for the mock method. We usually use it when we need to set a class that we don't exactly want it to run it's methods, so we mock then to return something that we need for our test to work.
You can learn more about tests with this tutorial: https://www.vogella.com/tutorials/JUnit/article.html#junittesting
----[Edit]----
If you wanted to mock the LocalClass, you were gonna need to do something like this:
#PrepareForTest({LocalClass.class, A.class})
#RunWith(PowerMockRunner.class)
public class ATest{
A a = new A();
#Test
public void methodATest(){
PowerMockito.mockStatic(LocalClass.class);
PowerMockito.when(LocalClass.getNumber()).thenThrow(new Exception());
...
}
}
But, the getNumber() method should be static for it to work.
And, since you can not use PowerMockito, it's not possible to mock the class.
----[Edit]----
#PrepareForTest({AnotherLocalClass.class, A.class})
#RunWith(PowerMockRunner.class)
public class ATest{
A a = new A();
#Test
public void methodATest(){
PowerMockito.mockStatic(AnotherLocalClass.class);
PowerMockito.when(AnotherLocalClass.getNumber()).thenThrow(new Exception());
a.methodAa(...);
...
}
}
But again, since static method belongs to the class, there is no way in Mockito to mock static methods.
public class A{
private final B b;
public void meth() {
//Some code
Integer a = b.some_method(a,fun(b));
//Some code
}
private fun(int b) {
return b;
}
}
when(b.some_method(anyInt(),anyInt())).thenReturn(100)
How to mock the externally dependency when writing unit tests for class A. When i mock dependency in the above way, the value of "a" is not getting assigned to 100 as expected.
Actually the answer of Jakub is correct. Maybe you need an example to understand how to do it. Check the main method and the contructor of my example.
public class A {
private final B b;
public A(B b) {
this.b = b;
}
public void meth() {
//Some code
Integer a = b.some_method(5,fun(5));
//Some code
System.out.println(a);
}
private int fun(int b) {
return b;
}
public static void main(String[] args) {
B b = Mockito.mock(B.class);
when(b.some_method(anyInt(), anyInt())).thenReturn(100);
new A(b).meth();
}
}
With the constructor you have to set B with your mock (see the last third line in the main method).
When you run the main method you will see the output of the System.out and it is 100.
You can use powermock library to mock final object. This is the implementation from their wiki.
Testing class:
public class StateFormatter {
private final StateHolder stateHolder;
public StateFormatter(StateHolder stateHolder) {
this.stateHolder = stateHolder;
}
public String getFormattedState() {
String safeState = "State information is missing";
final String actualState = stateHolder.getState();
if (actualState != null) {
safeState = actualState;
}
return safeState;
}
}
Test snippet:
StateHolder stateHolderMock = createMock(StateHolder.class);
StateFormatter tested = new StateFormatter(stateHolderMock);
expect(stateHolderMock.getState()).andReturn(expectedState);
// PowerMock.replay(..) must be used.
replay(stateHolderMock);
You can find full sample here.
You have to change your constructor in class A to parameterized.
Create a object by passing mock object B created using powermock
I am refactoring a Hibernate mapped object Gadget to remove getIntFieldValue and setIntFieldValue and changing my code to retrieve that value from a DAO object, which is created using a Factory and to which a Gadget is passed.
public class GadgetPropertyAccessFactory {
public static GadgetPropertyDAO getGadgetPropertyDAO(Session dbSessn){
if(getSomeBooleanFromDB(dbSessn)) {
return new TrueImplGadgetPropertyDAO();
} else {
return new FalseImplGadgetPropertyDAO();
}
}
...
The test code looks like this:
//this mocks a Gadget
Gadget gadget = createGadget();
//this is to be replaced
when(gadget.getIntFieldValue()).thenReturn(2);
DoerClass doerClass = new DoerClass(null, gadget);
List<Result> doerResults = doerClass.produceResults();
for (Result doerResult : doerResults) {
//...
}
The DoerClass looks something like this
Session dbSessn;
Gadget gadget;
public DoerClass(Session dbSessn, Gadget gadget) {
this.dbSessn = dbSessn;
this.gadget = gadget;
}
public List<Result> produceResults() {
//this is to be replaced
int intFieldValue = this.gadget.getIntFieldValue()
//with
//GadgetPropertyDAO gadgPropDAO = GadgetPropertyAccessFactory.getGadgetPropertyDAO(this.dbSessn);
//int intFieldValue = gadgPropDAO.getDeviceIntFieldValue(this.gadget);
//generate List<Result> based on intFieldValue
}
My problem is that before I was able to conveniently mock what getIntFieldValue will return in produceResults but now that I am using a statically returned DAO, I do not know if it is possible to mock what GadgetPropertyDAO.getDeviceIntFieldValue(this.gadget) will return.
Is a mock possible without changing my method signatures (API)?
I agree with Tom G: Mockito and dependency injection (and arguably Java itself) are really designed for instances much more than static methods—it's the only way to take advantage of Java's polymorphic advantages. If you switch to making your factory an instance, it would look like this:
public class GadgetPropertyAccessFactory {
public GadgetPropertyDAO getGadgetPropertyDAO(Session dbSessn){
if(getSomeBooleanFromDB(dbSessn)) {
return new TrueImplGadgetPropertyDAO();
} else {
return new FalseImplGadgetPropertyDAO();
}
} // ...
}
public class DoerClass {
Gadget gadget;
Session dbSessn;
// Sets default implementation. Constructor injection would also work.
GadgetPropertyAccessFactory gpaFactory = new GadgetPropertyAccessFactory();
public DoerClass(Session dbSessn, Gadget gadget) {
this.dbSessn = dbSessn;
this.gadget = gadget;
}
public List<Result> produceResults() {
GadgetPropertyDAO gadgPropDAO =
gpaFactory.getGadgetPropertyDAO(this.dbSessn);
int intFieldValue = gadgPropDAO.getDeviceIntFieldValue(this.gadget);
// ...
}
}
// in your test
DoerClass doerClass = new DoerClass(null, gadget);
GadgetPropertyAccessFactory mockFactory =
Mockito.mock(GadgetPropertyAccessFactory.class);
doerClass.gpaFactory = mockFactory;
// ...
Another option is to live with and manage your testing gap:
public List<Result> produceResults() {
return produceResultsInternal(gpaFactory.getGadgetPropertyDAO(this.dbSessn));
}
/** Visible only for testing. Do not call outside of tests. */
List<Result> produceResultsInternal(GadgetPropertyDAO gadgPropDAO) {
int intFieldValue = gadgPropDAO.getDeviceIntFieldValue(this.gadget);
// ...
}
...which then allows you to test against produceResultsInternal with a mock, which gets you 80% tested with 20% of the grief.
I'm trying to test implementations of a Collections interface using JUnit4 Parameterized tests. My test class has two tests:
#RunWith(Parameterized.class)
public class CollectionsTest {
private Collection<String> col;
private Collection<String> other;
public CollectionsTest(Collection<String> c, Collection<String> other) {
this.col = c;
this.other = other;
}
#Parameterized.Parameters
public static java.util.Collection<Object[]> tokenStreams() {
return (java.util.Collection<Object[]>) Arrays.asList(new Object[][] {
{ new DSLinkedList<String>(), new DSLinkedList<String>() } });
}
#Test
public final void isEmpty() {
assertTrue(col.getClass().getName() + ".isEmpty() should return true when collection contains no elements", col.isEmpty());
col.add("Stringthing");
assertFalse(col.getClass().getName() + ".isEmpty() should return false when collection contains elements", col.isEmpty());
}
#Test
public final void size() {
assertEquals(col.getClass().getName() + ".size() should be 0 for an empty collection.", 0, col.size());
col.add("String");
assertEquals(col.getClass().getName() + ".size() should be 1 for a collection with one element.", 1, col.size());
}
}
The second test (size()) always fails: at the time of the first assertion, col contains a single element stringThing, because I inserted an element in the isEmpty() test.
How do I clean the parameterized objects between tests?
If I wasn't using a parameterized test, I'd use #Before with a setup() method: should I be using reflection and a setup method here to recreate the col and other objects? (I haven't done this because I don't know which Collection implementation each test is running beforehand: if I have to manually write code using reflection to determine this, what's the point of Parameterized tests?)
My understanding is that the Parameterized tests call the constructor before each test, which should 'reset' my objects cleanly: why is this not the case?
Parameterized creates a new CollectionsTest object before each tests and calls the constructor, but it passes the same DSLinkedList objects each time, tokenStreams() is called only once for whole testcase. You should clean the lists in the constructor yourself.
In Java 8 this can be done fairly cleanly using lambda expressions and the utility class java.util.function.Supplier. Instead of providing an instance of the parameter type, you provide a lambda which supplies a new instance each time it is evaluated. JUnit passes the lambda to the constructor for each test case, where a new instance is created with a call to get().
#RunWith(Parameterized.class)
public class CollectionsTest {
private Collection<String> col;
private Collection<String> other;
public CollectionsTest(Supplier<Collection<String>> c, Supplier<Collection<String>> other) {
this.col = c.get();
this.other = other.get();
}
#Parameterized.Parameters
public static java.util.Collection<Object[]> tokenStreams() {
Supplier<Collection<String>> c1 = () -> new DSLinkedList<String>();
Supplier<Collection<String>> c2 = () -> new DSLinkedList<String>();
return Arrays.asList(new Object[][] { { c1, c2 } });
}
#Test
public final void isEmpty() {
assertTrue(col.getClass().getName() + ".isEmpty() should return true when collection contains no elements", col.isEmpty());
col.add("Stringthing");
assertFalse(col.getClass().getName() + ".isEmpty() should return false when collection contains elements", col.isEmpty());
}
#Test
public final void size() {
assertEquals(col.getClass().getName() + ".size() should be 0 for an empty collection.", 0, col.size());
col.add("String");
assertEquals(col.getClass().getName() + ".size() should be 1 for a collection with one element.", 1, col.size());
}
This is a late response. But I had the same dilemma and I solved it like this:
#RunWith(Parameterized.class)
public class CollectionsTest {
private Collection<String> col;
private Collection<String> other;
private Class<Collection> source1;
private Class<Collection> source2;
public CollectionsTest(Class<Collection> first, Class<Collection> second) {
this.source1 = first;
this.source2 = second;
}
#Parameters
public static Collection<Object[]> instancesToTest() {
return Arrays.asList(new Object[][] {
{ DSLinkedList.class, DSLinkedList.class },
{ OtherCollection.class, MyCollection.class }
});
}
#Before
public void setUp() throws Exception {
this.col = source1.newInstance();
this.other = source2.newInstance();
}
. . .
This approach works as long as your classes have a default constructor (no arguments).
The #Before setup() method gets called before each test and creates a new instance for your objects.
To use non-default constructors yo can use getConstructor() to choose which constructor you want:
this.col = source1.getConstructor(String.class).newInstance("Hello object");
You can create new objects within your tests too, using the same technique (e.g. Collection<String> c1 = source1.newInstance()), those tests have to throw an Exception (you will get a compile time error if they don't)
Well, you are changing the member variable value though. So, are you expecting the constructor to be called before each test? Also, as per the documentation of Parameterized. Your Test class instance would be provided with the data values in the #Parameters method. It isnt every test it is the instance of the class.
Parameterized