8

I am using spring in my application and I want to write unit tests for all my classes. I call few external webservices from my application and i want to mock them using Mockito since I just want to test my functionality.

Lets say I have the following scenario

This is my webservice interface

public interface MyWebService {
    public String getSomeData(int id);
}

I use the above service this way

public interface MyService {
    int doSomethingElse(String str);
}

public class MyServiceImpl implements MyService {

    private MyWebService myWebService;

    int doSomethingElse(String str) {
        .....
        myWebService.getSomeData(id);
        ...
    }
}

public interface MyService1 {
    Stirng methodToBeTested();
}


public class Class1 implements MyService1{
    @Resource
    private MyService myService;

    public Stirng methodToBeTested() {
        myService.doSomethingElse("..");
    }
}

I wrote the uint test case as below. I am spying MyService here so as to run the unit test.

public class class1Test {

    @Spy
    MyService myService;

    @Resource
    @InjectMocks
    Class1 class1;

    public void setUPTest() {
        MockitoAnnotations.initMocks(this);
    Mockito.doReturn(123).when(myService).doSomethingElse("someString");
    }

    @Test
    public void methodToBeTestedTest() {
        this.setUPTest();
            ...
            class1.methodToBeTested();
    }

}

When I run the test, what I see is that, I get the value from the webservice insted of what i mention while stubbing.

Can anyone help me with this?

rahul
  • 393
  • 1
  • 4
  • 20
  • See also http://stackoverflow.com/questions/2457239/injecting-mockito-mocks-into-a-spring-bean – Vadzim Oct 17 '13 at 10:57

6 Answers6

6

I solved this by using spring java config. I extended my default config file in my test config file.

    @Configuration
    public class TestConfig extends DefaultConfig {

      @Bean
      public MyService myService() {
        return Mockito.spy(new MyServiceImpl());
      }
    }

Now my test class goes like this

public class class1Test {

    @Resource
    MyService myService;

    @Resource
    Class1 class1;

    public void setUPTest() {
        MockitoAnnotations.initMocks(this);
    Mockito.doReturn(123).when(myService).doSomethingElse("someString");
    }

    @Test
    public void methodToBeTestedTest() {
        this.setUPTest();
            ...
            class1.methodToBeTested();
    }

}
rahul
  • 393
  • 1
  • 4
  • 20
3

A @Spy is used to spy on what happens when calling services (and useful to eg. assert the presence or absence of transitive method invocations), what you want is the @Mock annotation:

public class class1Test {
    @Mock MyService myService;
    ...

This will result in all myService methods returning null, bar those you override with doReturn/when.

Incidentally, rather than calling setUpTest() from your test methods, you should annotate it with @Before.

Cheers,

Anders R. Bystrup
  • 15,729
  • 10
  • 59
  • 55
  • I have used spy here because, there are other methods in MyService which dosent need to be stubbed.(This is just a sample code which resembles mine) – rahul Mar 26 '13 at 11:43
3

To replace your Bean with mock in some test use Springockito or better Springockito-annotations.

Something like this should work:

@ContextConfiguration(loader = SpringockitoContextLoader.class,
    locations = "classpath:/context.xml")
public class SpringockitoAnnotationsMocksIntegrationTest extends AbstractJUnit4SpringContextTests {

    @WrapWithSpy
    private MyService innerBean;

    @Resource  
    Class1 class1;

    public void setUPTest() {        
        Mockito.doReturn(123).when(myService).doSomethingElse("someString");
    }

    @Test
    public void methodToBeTestedTest() {
    this.setUPTest();
        ...
        class1.methodToBeTested();
    }

}

Michail Nikolaev
  • 3,733
  • 22
  • 18
  • I have seen the above link. How do I inject "myService" spy into "class1" using springockito. In Class1, "MyService" is private and has no setter. – rahul Mar 26 '13 at 13:17
  • @coder, updated. If in your real context myService is injected to Class1 - it will be injected with WrapWithSpy too. – Michail Nikolaev Mar 26 '13 at 13:31
  • I am using spring java config for initialisation of beans, springockito dosent support it. – rahul Mar 28 '13 at 07:25
  • @coder : seems to work with SpringockitoAnnotatedContextLoader.class – YoelBen Apr 11 '14 at 16:22
  • Thanks! That solved my issue. But I used "ReplaceWithMock" with "Autowired" annotations combination to spy on a real spring bean. – Azee Sep 03 '14 at 11:35
2

Do you mean anyString() rather than "someString" in your setUp method? This can also be eq("someString") if you are calling your method with a specific string.

From my understanding of Mockito I don't use spys since they probably indicate a class design issue. Why don't you @Mock the whole of MyService, so;

@Mock MyService myService;


public void setUpTest() {
    MockitoAnnotations.initMocks(this);
    when(myService.doSomethingElse(anyString)).thenReturn(123);
}
BrantApps
  • 6,362
  • 2
  • 27
  • 60
  • @coder I had a similar class design until I came to test it when I realised my class was doing too many things making it difficult to unit test. Consider splitting the web-service work out to a handler class. This way you can construct your class with the mock'ed handler and do away with the ````@Spy````. Any calls to the ws can then be simply mocked with the traditional non-spy tooling. – BrantApps Mar 26 '13 at 11:49
  • That would solve the problem but the sad thing is that I cant change the original implementation of MyService or MyServiceImpl. – rahul Mar 26 '13 at 11:56
  • Ah right, yes you are correct to use a spy then. I didn't realise. They are especially useful when dealing with 3rd party/legacy code. Does my advice about the Matchers yield better mocking results? – BrantApps Mar 26 '13 at 11:59
  • No. The only problem I am facing here is with "@Resource" and "@InjectMocks" used on same variable. The variable gets initialised first with "@Resouce" then injection dosent happen. – rahul Mar 26 '13 at 12:05
2

Modified,

    public class class1Test {

    @Mock
    private MyService myService;

    private Class1 class1;

    @Before
    public void onceBeforeEachTest() {
        MockitoAnnotations.initMocks(this);
         this.class1 = new Class1(myService); 
        Mockito.when(myService).doSomethingElse(anyString()).thenReturn(123);
    }

    @Test
    public void methodToBeTestedTest() {
            class1.methodToBeTested();
    }
}
Sajan Chandran
  • 11,287
  • 3
  • 29
  • 38
1

This should suits your need:

@RunWith(MockitoJunitRunner.class)
public class class1Test {

    @Mock
    private MyService myService;

    private Class1 class1;

    @Before
    public void setUp() {
        this.class1 = new Class1(myService); // creates this constructor.
    }

    @Test
    public void methodToBeTestedTest() {
        this.class1.methodToBeTested();
        Mockito.verify(this.myService).doSomethingElse(/* put expected arg here */);
    }
}

See also the official doc.