EasyMock "Unexpected method call" despite of expect method declaration

24,454

Solution 1

when you write something like,

expect(contextMock.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)))
        .andReturn(someIntent1).once();

Easymock expects the registerReceiver method to be called with exact parameter with which it is told to expect,

So to avoid this ,while expecting any method and writing its behaviour, use anyObject() method like this:-

expect(contextMock.registerReceiver(null, EasyMock.anyObject(IntentFilter.class)))
            .andReturn(someIntent1).once();

by this, easymock understands that it has to mock all the calls to expected method, when any object of IntentFilter is passed as a parameter

Hope this helps! Good luck!

Solution 2

By default, EasyMock use an equal matcher. So it means that the IntentFilter parameter will be compared using equals.

I'm not sure a working equals was coded on IntentFilter. Looking at the documentation, it's probably not the case. So this is why nothing matches.

The only surprising thing is that the toString on IntentFilter used to show the error message is the one of Object. Both all three have the same address (c009614f). Which is weird because it would mean that they all are the same instance. Which is impossible. So I'll stick with my answer.

To fix it, depending if you really care about the parameter, you could use anyObject() or a dedicated comparator

Solution 3

For people running into this issue, note that the number of times a source code method is called within a test should be equal to the number of times an expect is set.

For eg: if the following expectation is set in test code,

expect(contextMock.registerReceiver(null, EasyMock.anyObject(IntentFilter.class)))
        .andReturn(someIntent1).once();

that means, when the test code is run, it should have exactly 1 call to the registerReceiver method. Otherwise, we would end up with different assertion exceptions like so:

java.lang.AssertionError: 
  Unexpected method call Context.registerReceiver(null, android.content.IntentFilter@c009614f):
    Context.registerReceiver(null, android.content.IntentFilter@c009614f): expected: 1, actual: 0
    Context.registerReceiver(null, android.content.IntentFilter@c009614f): expected: 1, actual: 0

The expected and actual numbers start varying depending on the number of calls.

Share:
24,454
apex39
Author by

apex39

Medium

Updated on May 06, 2021

Comments

  • apex39
    apex39 about 3 years

    My EasyMock's expected method is perceived as unexpected, although I do not use and strict mocks, and the method is already declared before being replied.

    Test fails in this line of code:

    Intent batteryIntent = context.getApplicationContext().registerReceiver(null,
            new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
    

    Test:

    @Before
    public void setUp() {
        mocksControl = createControl();
        contextMock = mocksControl.createMock(Context.class);
        //(...)
    }
    
    @Test
    public void test() {
        expect(contextMock.getApplicationContext()).andReturn(contextMock).anyTimes();
        expect(contextMock.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)))
            .andReturn(someIntent1).once();
        expect(contextMock.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)))
            .andReturn(someIntent2).once();
        mocksControl.replay();
        //(...) tested method is invoked on class under the test
    }
    

    Error I get:

    java.lang.AssertionError: 
      Unexpected method call Context.registerReceiver(null, android.content.IntentFilter@c009614f):
        Context.registerReceiver(null, android.content.IntentFilter@c009614f): expected: 1, actual: 0
        Context.registerReceiver(null, android.content.IntentFilter@c009614f): expected: 1, actual: 0
    
  • apex39
    apex39 over 8 years
    Thank you, it helped! Then I received IllegalStateException: 2 matchers expected, 1 recorded what contributed to this shape of final solution: expect(contextMock.registerReceiver((BroadcastReceiver) isNull(), anyObject(IntentFilter.class))) .andReturn(someIntent).once();
  • apex39
    apex39 over 8 years
    Thank you for the technical insight :) Is it possible for EasyMock to have feature of checking if working equals is coded in the object?
  • Henri
    Henri over 8 years
    Interesting idea. Can you please fill a feature request here? github.com/easymock/easymock/issues
  • Andy Foster
    Andy Foster about 4 years
    This is a copy-paste of the error EasyMock spits out.