Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking internal instantiated object

I'm writing a test class for testing my 'ImporterService' class. This service reads an InputStream and creates an Object from it's data. The Object, in this case a Builder class, is instantiated within the 'ImporterService' class. To test my 'ImporterService' class I need to verify the invocations on the Builder class. For this I want to use a Mocking framework, however how is it possible to create a mock instance of the 'Builder' object outside the 'ImporterService'?

The method of my 'ImporterService' class looks like:



    public Builder importFrom(BufferedReader reader) throws IOException {
        String someValue = readFrom(reader);
        Builder builder = new Builder();   // I need to mock this Builder object...
        builder.someMethod(someValue);     // to see of a method is called with the expected value
    }

I was thinking about moving the creation of the Builder class into a protected method which I can override on setup of the test. But this solution seems not very nice to me as the 'ImporterService' class is leaking some internal logic and makes it possible to override the method by other classes which I do not want.

like image 393
user1024435 Avatar asked Dec 15 '11 09:12

user1024435


People also ask

What does mocking an object do?

Using mock objects allows developers to focus their tests on the behavior of the system under test without worrying about its dependencies. For example, testing a complex algorithm based on multiple objects being in particular states can be clearly expressed using mock objects in place of real objects.

What's the difference between mock and spy objects?

Mocks are used to create fully mock or dummy objects. It is mainly used in large test suites. Spies are used for creating partial or half mock objects. Like mock, spies are also used in large test suites.

Does mock create a object?

Mockito provides various methods to create mock objects. mock() creates mocks without bothering about the order of method calls that the mock is going to make in due course of its action.

Can we set value to mock object?

You can set the mock object property to the value returned by the mock object method. To achieve this, specify separate behaviors for the method and the property. You can specify one behavior at a time.


2 Answers

If you use any dependency injection library (like Spring) you could inject mock object instead of builder to ImporterService class. Or you could replace call to constructor with call to factory and use factory, that returns mocks in test code.

like image 69
dbf Avatar answered Oct 13 '22 15:10

dbf


Yes, you can either do as you suggested or :

Create a Factory class in which you create Builder objects and assign it to the reader class. In your unit tests, mock this factory and force it to build a Builder of your choice that you can check for method calls in your unit test.

Here is an example using EasyMock showing how you can achieve this:

public class Reader{
   private BuilderFactory factory = new BuilderFactory(); // Use production factory by default
   public Builder importFrom(BufferedReader reader) throws IOException {
        String someValue = readFrom(reader);
        Builder builder = factory.buildBuilder();
        builder.someMethod(someValue);     // to see of a method is called with the expected value
    }
}

In your unit tests you do the following:

Reader classUnderTest = new Reader();
BuilderFactory fakeFactory = EasyMock.createNiceMock(BuilderFactory.class);
Builder builder = EasyMock.createMock(Builder.class);
EasyMock.expect(fakeFactory.buildBuilder()).andReturn(builder);
builder.someMethod("value here");
EasyMock.expectLastCall().once();
EasyMock.replay(fakeFactory, builder);
classUnderTest.importFrom(bufferReader);
// Very that all calls were correctly performed on the builder
EasyMock.verify(builder);
like image 37
GETah Avatar answered Oct 13 '22 17:10

GETah