How to use mock of one class inside another to JUNIT test a void method for capturing arguments? - unit-testing

Here I Have a class A which is implementing method1.
class A{
public void method1(String name){
classB b = new classB();
// Some operations
b.method2(argument1);
}
}
I want to capture the argument passed to method2 for which I wrote the below code.
I got the error as the mock is not invoked when I did verify to capture the argument in the below code. Please let me know how to execute this successfully by invoking the mock to capture the argument passed to method2
class ATest{
String name = "name";
#Before
public void setup{
class A = new class A();
class B = Mockito.mock(classB.class);
}
public void testmethod1()
{
A.method1(name);
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
Mockito.verify(B, Mockito.times(1)).method2(captor.capture());
String actual = captor.getValue();
assertEquals("some data", actual);
}
}

Class B needs to be a dependency of Class A for you to be able to mock it properly. Or it can be a parameter.
Class A{
public final B b;
public A(B b){
this.b = b
}
public void method1(String name){
// Some operations
b.method2(argument1);
}
}
then in your test pass in the mock when you instantiate class A
class ATest{
private B b;
private A a;
#Before
public void setup{
b = Mockito.mock(B.class);
a = new A(b);
}
// tests...
}

Related

Mockito Spy cauing issues with Mocked Functions

lets say you have a function fun() in class A that I want to test fun() calls 2 dependancy fun1() and fun2() now it also calls fun3() which is of the same class A.
So here is how my class looks like :
class A {
B b;
C c;
#Inject
A(B b, C c) {
this.b = b;
this.c = c;
}
fun() {
try {
b.fun1();
c.fun2("success");
} catch (Exception) {
c.fun2("Failure")
}
fun3();
}
fun3() {
//Code
}
}
The Test that I wrote :
public class ATest {
#Mock
B b;
#Mock
C c;
#InjectMocks
A a;
#Mock
Fun1Response fun1response;
#Test
public void myTest() {
when(b.fun1(any())).thenReturn(fun1response);
A aSpy = Mockito.spy(a);
doNothing().when(aSpy).fun3();
doNothing().when(c).fun2(any());
aSpy.fun();
verify(c).fun2(eq("success"));
verify(a).fun3();
}
}
It is giving me this error while runnign the test:
Wanted but not invoked:
c.fun2(<any>)
[junit] Actually, there were zero interactions with this mock.

EXPECT_CALL of function within same class using c++ & gtest

Lets assume i have class B and it has two functions and one function is calling other:
Class B {
virtual void funParent();
virtual void funChild();
};
void B::funChild(){}
void B::funParent()
{
funChild();
}
===============================================
class MockB : public B
{
MOCK_METHOD0(funChild,void()); MOCK_METHOD0(funParent,void());
}
===============================================
class TestClass : public testing::Test {
..
};
//Test case for checking function call of funChild() in funParent()
TEST_F(TestClass,testFunParent)
{
//I want to test function call "funChild" using EXPECT_CALL.
//EXPECT_CALL(__somePtr__,funChild()).Times(Atleast(1));
//B b;
//b.funParent();
}
I am wondering how do i achieve this, since it is a memeber function of same class.

How to test a class that sets up its properties on constructor?

I have a lot of classes implementing some interfaces and I built some classes that "coordinates" the usage. So, I created a base class that contains the orchestration, and built a class for each combination of these interface implementations that I needed. Something like this:
public abstract class BaseDirector
{
public IInterfaceA A { get; set; }
public IInterfaceB B { get; set; }
public virtual void Do()
{
A.Do();
B.Do();
}
}
public class Director1: BaseDirector
{
public Director1()
{
A = new A1();
B = new B2();
}
}
public class Director2: BaseDirector
{
public Director2()
{
A = new A2();
B = new B12();
}
}
It smells bad and I don't see how I can test this. Can someone give some directions on how to test this? Do I need to change the approach on "director" classes?
You make each implementation have constructors that support dependency injection (passing in values instead of creating them internally) I'm not 100% sure in c#, but I think you can require a constructor like this by creating a similar constructor in the base class. But either way you can just 'manually' make both no-op and D.I. constructor for each impl.
public class Director1: BaseDirector
{
public Director1()
{
A = new A1();
B = new B2();
}
public Director1(A a, B b) // Make a constructor that handles "dependency injection"
{
A = a;
B = b;
}
}
public class Director2: BaseDirector
{
public Director2()
{
A = new A2();
B = new B12();
}
public Director2(A a, B b) // Make a constructor that handles "dependency injection"
{
A = a;
B = b;
}
}
This allows you to 'inject' values you want for testing purposes.

How to mock this class

class A
{
public:
void doFirstJob()
{
// Do first Job.
}
}
class B : public A
{
public:
virtual void doSecondJob()
{
// Do Second Job.
}
}
class C
{
public:
void doSomething() {
b->doFirstJob();
b->doSecondJob();
}
private:
B* b;
}
Now I should write unit test code for class C, then I'll write a mock for class B, but the problem is how to mock the method doFirstJob().
Bluntly, I want know how to mock the non-virtual method of the parent class???
Can any one help me ??
Typemock Isolator++ supports mocking non virtual methods of a parent class (same as faking a method of the class under test).
See following example:
class A
{
public:
int doFirstJob()
{
return 0;
}
};
class B : public A
{
};
class C
{
public:
int doSomething()
{
return b->doFirstJob();
}
void setB(B* to)
{
b = to;
}
private:
B* b;
};
In the test You create a fake of B -> change the behavior of doFirstJob to return 3 -> continue with your test as you would normally write it.
TEST_CLASS(NonVirtualMethod)
{
public:
TEST_METHOD(NonVirtualMethodTestOfBaseClass)
{
B* fakeB = FAKE<B>();
WHEN_CALLED(fakeB->doFirstJob()).Return(3);
C c;
c.setB(fakeB);
int first = c.doSomething();
Assert::AreEqual(3,first);
}
}
You can find more examples here.

Mock Abstract Parent Method of Field

FIRSTLY: I am testing legacy code.
I am testing an abstract class we will call Class A.
Class A has Field of type Class B. Class B is a child of Abstract base class we will call B_Base.
MY PROBLEM: In a method of class A, the instance of class B calls a method in B_Base.
I have tried mocking a B class and then replacing the Field with the mocked B Class, however, everytime it runs the parent method, there is a NullPointerException in the Mockito.when() method, meaning the parent B_Base class is NOT mocked.
Here is an idea of what the code looks like.
public abstract class A { //this is the class Im testing.
public B bInstance;
public boolean methodIAmTesting {
int hello = bInstance.method_Only_In_B_Base();
...
}
}
The test:
public class TestClass extends A {
//here is the constructor etc..
#Test
public void test1 {
TestClass x = new TestClass();
bInstance = Mockito.mock(B.class);
// ERROR IS HERE V
Mockito.when(bInstance.method_Only_In_B_Base()).thenReturn(50);
Assert.assertTrue(x.methodIAmTesting());
}
}
As J L mentioned, you've actually got two instances kicking around, because your TestClass extends A.
What you have:
public class TestClass extends A {
#Test public void test1() {
Class TestClass x = new TestClass();
bInstance = Mockito.mock(B.class);
// ...
}
}
What you want:
public class TestClass extends A {
#Test public void test1 {
Class TestClass x = new TestClass();
x.bInstance = Mockito.mock(B.class); // <-- replace bInstance on x
// ...
}
}
JUnit creates an instance of your test class automatically, so when you call x = new TestClass() you're creating a separate instance for test, and your call for bInstance = mock(B.class) is setting the mock on the instance that JUnit creates rather than the x instance you create.
Note that it's very unusual to have a JUnit test class subclass the system under test. Consider a design like this instead:
#RunWith(JUnit4.class)
public class ATest {
private static class TestClass extends A {
// ...
}
#Test public void test1 {
Class TestClass x = new TestClass();
x.bInstance = Mockito.mock(B.class);
// ...
}
}