Hi devs,

I've been writing tests in druid for a little bit now and wanted to hear
your thoughts on using EasyMock as the mocking framework.

I've found it pretty tedious to write tests using easy mock because it's
very verbose, and requires me to do a lot of set up for the mock objects.
Because of this setup work, the mocks tend to be very tightly coupled with
the implementation which makes it harder to refactor in the future. The
extra stubbing work also discourages me from adding more tests. *IMO, this
makes it harder for us to write well tested code.*

TL;DR at the bottom with questions for those on this list

I've used Mockito in the past, and find it to be more fluent when writing
tests. See this example for a side by side comparison.

*Using Mockito* -  create a mock object that returns mock objects for every
function call.

@Mock(answer = Answers.RETURNS_MOCKS)
private IndexTask.IndexIngestionSpec ingestionSpec;

*Using EasyMock*

@Mock
private IndexTask.IndexIngestionSpec ingestionSpec;

@Mock
private DataSchema dataSchema;

@Mock
private IndexTask.IndexIOConfig indexIOConfig;

@Mock
private IndexTask.IndexIOConfig indexTuningConfig;

@Before
public void setUp() throws IOException
{

  EasyMock.expect(ingestionSpec.getDataSchema())andStubReturn(dataSchema);

  EasyMock.expect(ingestionSpec.getIndexIOConfig())andStubReturn(indexIOConfig);

  
EasyMock.expect(ingestionSpec.getIndexTuningConfig())andStubReturn(indexTuningConfig);

  EasyMock.replay(ingestionSpec);

  ...

Now if the interface of ingestionSpec changes to add a new method, we need
to stub that in the tests as well. If getDataSchema() is called an extra
time the mock throws an exception because it's not expected that the
function will be called twice
IMO this makes them brittle because they are tightly coupled to the code.

With Mockito, you only need to mock objects that you want to interact with
in the tests.

@Mock(answer = Answers.RETURNS_MOCKS)
private IndexTask.IndexIngestionSpec ingestionSpec;

@Mock(answer = Answers.RETURNS_MOCKS)
private DataSchema dataSchema;

@Before
public void setUp() throws IOException
{

  Mockito.when(ingestionSpec.getDataSchema()).thenReturn(dataSchema);

  Mockito.when(dataSchema.getDimensionsSpec()).thenReturn(dimensionsSpec);

  ...

Another feature of Mockito I like is that it allows you to spy real
objects. So if you have a class that creates a File, you can spy the
function and give it a fake File to operate on instead of having your tests
have to create real files. For example, below is some test code that
doesn't get a real InputSourceReader which means the test doesn't need to
add any set up code to get the reader. It simply says, if you need to use
an inputSourceReader - use this one.

target = Mockito.spy(new IndexedTableSupplier(INDEX_KEYS,
ingestionSpec, () -> tmpDir));
Mockito.doReturn(inputSourceReader).when(target).getInputSourceReader(dataSchema,
tmpDir);

Here's a list of similarities/ differences between the frameworks -
https://github.com/mockito/mockito/wiki/Mockito-vs-EasyMock
Here's a stackoverflow post asking about maintainability in large projects
-
https://stackoverflow.com/questions/2864796/easymock-vs-mockito-design-vs-maintainability

*TL;DR: *Am I using EasyMock incorrectly? Do these features exist and I
just don't know how to use them?

What would it take for us to try another framework like Mockito?

Reply via email to