0

I have a very basic understanding in mocking/stubbing.

When you create a stub in test code like:

test h = mock(test);
when(h.hello()).thenReturn(10);

and in source logic I have code like this:

test src = new test();
src.hello();

Now will stub get invoked since I've stubbed the hello method or Since the instance is different will it not get stubbed? Is there any way to stub all instances of the class?

3 Answers3

2

You would need to use a factory pattern and inject a mocked factory into the class where the instances are being created.

So, if you want to write tests for some class Foo, which needs to create instances of Bar somewhere in its code, you would need to inject a BarFactory into Foo. Injection can happen the old fashioned way by passing a BarFactory into the constructor or a set method, or with a dependency injection framework like Guice. A brief example of the old-fashioned way:

class Foo {

    private final BarFactory mFactory;

    public Foo(BarFactory factory) {
        mFactory = factory;
    }

    public void someMethodThatNeedsABar() {
        Bar bar = mFactory.create();
    }

}

Now, in your test class you can inject a mocked BarFactory that can produce mocked instances of Bar:

Bar mockBar = mock(Bar.class);
BarFactory mockFactory = mock(BarFactory.class);
when(mockFactory.create()).thenReturn(mockBar);
Foo objectForTest = new Foo(mockFactory);
Dave
  • 4,282
  • 2
  • 19
  • 24
1

A better way to write testable code is not to create cooperating classes by new operator in class code, but to pass cooperating classes as constructor arguments.

class TestedClass{
private final Helper helper;
public TestedClass(Helper helper){
      this.helper = helper;
}

public aMethodUsesHelper(){
    //hello is weird name for method that returns int but it is link to your code
    int aVar =this.helper.hello();
    // ...
}
// ...

Then in test class:

Helper helper = mock(Helper.class);
when(helper.hello()).thenReturn(10);
TestedClass tested = new Tested(helper);
// ...
Patrick
  • 1,717
  • 7
  • 21
  • 28
JosefN
  • 952
  • 6
  • 8
  • Reflection to set the helper in testedclass to my mock is also on option right? Please correct me if I'm wrong. – user1192671 Dec 14 '13 at 11:03
  • Yes you can but only in case that it assigned to a field in constructor not dynamically created in the tested method. You can use special class loader to load mock version of the helper class but trust me that the best way is write easy testable code with cooperation classes passed in constructor. Tools like spring perfectly support it. – JosefN Dec 14 '13 at 20:20
  • Well I understand writing testable code. Right now I'm working with legacy code so I need a workaround for now. So What if the field in constructor is dynamically created but I make it assign to my mock while running my test? It should work right? – user1192671 Dec 16 '13 at 05:53
  • in this case you can use reflection, Field privateField = TestedClass.class.getDeclaredField("filedWithcooperatingClass"); privateStringField.setAccessible(true); privateStringField.set(TestedClass.class, mockock); – JosefN Dec 16 '13 at 08:14
1

You need to use the mocked instance to get the stub working. Cheers :)

Flying Dumpling
  • 1,294
  • 1
  • 11
  • 13