verify() wanted but not invoked...

14,360 views
Skip to first unread message

Russell Bateman

unread,
Jan 15, 2013, 1:38:17 PM1/15/13
to moc...@googlegroups.com
...except that a) yes, I did want it to be invoked and b) yes it was
invoked: I saw it get invoked as I stepped through in the debugger.

I mocked the method with specific information (an e-mail address) and
what to return when it happened (an array of account objects each with
that e-mail address). I watched in the debugger how it was called and
how it returned exactly the information I wanted.

Obviously, I can take out the verify statement, but that would thwart
some of the value of my unit test.

Note that this particular test file has two methods and the first
method, which does work, is almost identical and the exact, same verify
statement doesn't fail.

How can I investigate the Mockito data structures to determine why
Mockito doesn't think the class under test really called the mock?

Thanks,

Russ

P.S. Oh, and did I mention that Mockito rocks? I've just done some
low-key refactoring and my existing tests helped me catch all the places
I screwed up in the refactoring. This is just a little trifle I need to
clean up so that all my tests succeed.

Malte Finsterwalder

unread,
Jan 15, 2013, 2:53:59 PM1/15/13
to mockito
Is it possible that the arguments don't quite match between the actual call and the verify call?
Can you post some code and some output/error message you get from Moskito?




--
You received this message because you are subscribed to the Google Groups "mockito" group.
To post to this group, send email to moc...@googlegroups.com.
To unsubscribe from this group, send email to mockito+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/mockito?hl=en.


Russell Bateman

unread,
Jan 15, 2013, 4:39:21 PM1/15/13
to moc...@googlegroups.com
See code below...


On 1/15/2013 12:53 PM, Malte Finsterwalder wrote:
Is it possible that the arguments don't quite match between the actual call and the verify call?
Can you post some code and some output/error message you get from Moskito?


On 15 January 2013 19:38, Russell Bateman <ru...@windofkeltia.com> wrote:
...except that a) yes, I did want it to be invoked and b) yes it was invoked: I saw it get invoked as I stepped through in the debugger.

I mocked the method with specific information (an e-mail address) and what to return when it happened (an array of account objects each with that e-mail address). I watched in the debugger how it was called and how it returned exactly the information I wanted.

Obviously, I can take out the verify statement, but that would thwart some of the value of my unit test.

Note that this particular test file has two methods and the first method, which does work, is almost identical and the exact, same verify statement doesn't fail.

How can I investigate the Mockito data structures to determine why Mockito doesn't think the class under test really called the mock?

Thanks,

package com.abc.web.user.manager;

import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.bson.types.ObjectId;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import com.abc.web.user.dao.AccountDao;
import com.abc.web.user.dao.AddressDao;
import com.abc.web.user.dao.CallerDao;
import com.abc.web.user.dao.PaymentDao;
import com.abc.web.user.entity.Account;
import com.abc.web.user.entity.EntityTestSupport;
import com.abc.web.user.entity.Caller;
import com.abc.web.user.exception.AppException;
import com.abc.web.user.util.ApplicationProperties;

public class WalkFederatedAccountsTest
{
    private static final String   SCHMUCK_EMAIL = "sch...@abccorp.com";
    private static final String        PASSWORD = "test123";
    private static final String   ABC_CORP_NAME = "ABC Corp.";
    private static final String   ACMECORP_NAME = "Acme Corp.";
    private static final String    ACMELTD_NAME = "Acme, Ltd.";
    private static final String    ACMEASS_NAME = "Acme Associates, Inc.";
    private static final String    WALMART_NAME = "Walmart";
    private static final String ABC_CORP_ENTITY = "AbcCorp-entitykey";
    private static final String ACMECORP_ENTITY = "Caller1-entitykey";
    private static final String  ACMELTD_ENTITY = "Caller2-entitykey";
    private static final String  ACMEASS_ENTITY = "Caller3-entitykey";
    private static final String  WALMART_ENTITY = "Caller4-entitykey";

    private static final ObjectId ABC_CORPOID = new ObjectId( "000000000000000000000099" );
    private static final ObjectId ACMECORPOID = new ObjectId( "000000000000000000000011" );
    private static final ObjectId ACMELTDOID  = new ObjectId( "000000000000000000000022" );
    private static final ObjectId ACMEASSOID  = new ObjectId( "000000000000000000000033" );
    private static final ObjectId WALMARTOID  = new ObjectId( "000000000000000000000044" );

    private static Caller ABC_CORP;
    private static Caller ACMECORP;
    private static Caller ACMELTD;
    private static Caller ACMEASS;
    private static Caller WALMART;

    private static Account SCHMUCK;
    private static Account ACCOUNT1;
    private static Account ACCOUNT2;
    private static Account ACCOUNT3;
    private static Account ACCOUNT4;

    private WalkFederatedAccounts walker;

    @Mock private AccountDao accountDao;
    @Mock private AddressDao addressDao;
    @Mock private PaymentDao paymentDao;
    @Mock private CallerDao       callerDao;

    @Before
    public void setup()
    {
        ApplicationProperties.reloadProperties();
        MockitoAnnotations.initMocks( this );

        new StaticDataDaoMocks();
        EntityTestSupport.setEntityDaoMocks( accountDao, addressDao, paymentDao, callerDao );

        walker = new WalkFederatedAccounts();

            ABC_CORP = EntityTestSupport.constructCaller( ABC_CORPOID, ABC_CORP_ENTITY, ABC_CORP_NAME );
            ACMECORP = EntityTestSupport.constructCaller( ACMECORPOID, ACMECORP_ENTITY, ACMECORP_NAME );
            ACMELTD  = EntityTestSupport.constructCaller( ACMELTDOID,  ACMELTD_ENTITY,  ACMELTD_NAME );
            ACMEASS  = EntityTestSupport.constructCaller( ACMEASSOID,  ACMEASS_ENTITY,  ACMEASS_NAME );
            WALMART  = EntityTestSupport.constructCaller( WALMARTOID,  WALMART_ENTITY,  WALMART_NAME );
            SCHMUCK  = EntityTestSupport.constructAccount( SCHMUCK_EMAIL, ABC_CORPOID, PASSWORD );
            ACCOUNT1 = EntityTestSupport.constructAccount( SCHMUCK_EMAIL, ACMECORPOID, PASSWORD );
            ACCOUNT2 = EntityTestSupport.constructAccount( SCHMUCK_EMAIL, ACMELTDOID,  PASSWORD );
            ACCOUNT3 = EntityTestSupport.constructAccount( SCHMUCK_EMAIL, ACMEASSOID,  PASSWORD );
            ACCOUNT4 = EntityTestSupport.constructAccount( SCHMUCK_EMAIL, WALMARTOID,  PASSWORD );
            EntityTestSupport.addToCallerdata( ABC_CORP, ACMECORP_ENTITY, true,  true,  true,  true,  false );
            EntityTestSupport.addToCallerdata( ABC_CORP, ACMELTD_ENTITY,  true,  true,  true,  true,  false );
            EntityTestSupport.addToCallerdata( ABC_CORP, ACMEASS_ENTITY,  true,  false, true,  true,  false );
            EntityTestSupport.addToCallerdata( ABC_CORP, WALMART_ENTITY,  false, false, false, false, false );
            EntityTestSupport.addToCallerdata( ACMECORP, ABC_CORP_ENTITY, true,  true,  true,  true,  false );
            EntityTestSupport.addToCallerdata( ACMELTD,  ABC_CORP_ENTITY, true,  true,  true,  true,  false );
            EntityTestSupport.addToCallerdata( ACMEASS,  ABC_CORP_ENTITY, true,  false, true,  true,  false );
            EntityTestSupport.addToCallerdata( WALMART,  ABC_CORP_ENTITY, false, false, false, false, false );
            SCHMUCK.setFullname( "Schmuck at ABC Corp." );
            ACCOUNT1.setFullname( "Schmuck at Acme Corp." );
            ACCOUNT2.setFullname( "Schmuck at Acme, Ltd.." );
            ACCOUNT3.setFullname( "Schmuck at Acme Associates, Inc." );
            ACCOUNT4.setFullname( "Schmuck at Walmart" );
    }

    @Test
    public void testWalkAccounts_bypassword() throws AppException
    {
        List< Account > accounts = new ArrayList< Account >();
        accounts.add( SCHMUCK );
        accounts.add( ACCOUNT1 );
        accounts.add( ACCOUNT2 );
        accounts.add( ACCOUNT3 );
        accounts.add( ACCOUNT4 );

        // now mock the DAO methods called by CallerManager and AccountManager...
        when( accountDao.readAllByIdentity( SCHMUCK_EMAIL ) ).thenReturn( accounts );      this is mocked...
        when( callerDao.readByOid( ABC_CORPOID ) ).thenReturn( ABC_CORP );
        when( callerDao.readByOid( ACMECORPOID ) ).thenReturn( ACMECORP );
        when( callerDao.readByOid( ACMELTDOID ) ).thenReturn( ACMELTD );
        when( callerDao.readByOid( ACMEASSOID ) ).thenReturn( ACMEASS );
        when( callerDao.readByOid( WALMARTOID ) ).thenReturn( WALMART );

        walker.setCallingcalleroid( ABC_CORPOID );
        walker.setCallingcaller( callerDao.readByOid( ABC_CORPOID ) );
        walker.setIdentity( SCHMUCK_EMAIL );
        walker.setObject( "schmuck-...@schmucks-r-us.com" );

        walker.byPassword( new Date() ); ...and called inside here.

        // these calls into the DAO should have been made during this test...
        verify( callerDao ).readByOid( ABC_CORPOID );
        verify( accountDao ).readAllByIdentity( SCHMUCK_EMAIL );       --no error about this (and there shouldn't be)
        verify( callerDao ).readByOid( ABC_CORPOID );
        verify( callerDao ).readByOid( ACMECORPOID );
        verify( callerDao ).readByOid( ACMELTDOID );
        verify( callerDao ).readByOid( ACMEASSOID );
        verify( callerDao ).readByOid( WALMARTOID );

        verify( accountDao ).update( ACCOUNT1 );
        verify( accountDao ).update( ACCOUNT2 );
        verify( accountDao ).update( ACCOUNT3 );
    }

    @Test
    public void testWalkAccounts_byemail() throws AppException
    {
        List< Account > accounts = new ArrayList< Account >();
        accounts.add( SCHMUCK );
        accounts.add( ACCOUNT1 );
        accounts.add( ACCOUNT2 );
        accounts.add( ACCOUNT3 );
        accounts.add( ACCOUNT4 );

        // now mock the DAO methods called by CallerManager and AccountManager...
        when( accountDao.readAllByIdentity(  SCHMUCK_EMAIL ) ).thenReturn( accounts );
        when( callerDao.readByOid( ABC_CORPOID ) ).thenReturn( ABC_CORP );
        when( callerDao.readByOid( ACMECORPOID ) ).thenReturn( ACMECORP );
        when( callerDao.readByOid( ACMELTDOID ) ).thenReturn( ACMELTD );
        when( callerDao.readByOid( ACMEASSOID ) ).thenReturn( ACMEASS );
        when( callerDao.readByOid( WALMARTOID ) ).thenReturn( WALMART );

        walker.setCallingcalleroid( ABC_CORPOID );
        walker.setCallingcaller( callerDao.readByOid( ABC_CORPOID ) );
        walker.setIdentity( SCHMUCK_EMAIL );
        walker.setObject( "Test123" );

        walker.byEmail( null );    <------ accountDao.readAllByIdentity() called inside here

        // these calls into the DAO should have been made during this test...
        verify( callerDao ).readByOid( ABC_CORPOID );
        verify( accountDao ).readAllByIdentity( SCHMUCK_EMAIL );  --singled out as uncalled
        verify( callerDao ).readByOid( ABC_CORPOID );
        verify( callerDao ).readByOid( ACMECORPOID );
        verify( callerDao ).readByOid( ACMELTDOID );
        verify( callerDao ).readByOid( ACMEASSOID );
        verify( callerDao ).readByOid( WALMARTOID );

        verify( accountDao ).update( ACCOUNT1 );
        verify( accountDao ).update( ACCOUNT2 );
        verify( accountDao ).update( ACCOUNT3 );
    }
}


Failure Trace

Wanted but not invoked:

accountDao.readAllByIdentity(

     "sch...@abccorp.com"

);

-> at

com.abc.web.user.manager.WalkFederatedAccountsTest.testWalkAccounts_byemail(WalkFederatedAccountsTest.java:183)

Actually, there were zero interactions with this mock.

 

     at

com.abc.web.user.manager.WalkFederatedAccountsTest.testWalkAccounts_byemail(WalkFederatedAccountsTest.java:183)

     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

     at

sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

     at

sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

     at java.lang.reflect.Method.invoke(Method.java:597)

     at

org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)

     at

org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)

     at

org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)

     at

org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)

     at

org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)

     at

org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)

     at

org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)

     at

org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)

     at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)

     at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)

     at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)

     at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)

     at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)

     at org.junit.runners.ParentRunner.run(ParentRunner.java:236)

     at

org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)

     at

org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)

     at

org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)

     at

org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)

     at

org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)

     at

org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

 


Eric Lefevre-Ardant

unread,
Jan 16, 2013, 3:40:05 AM1/16/13
to moc...@googlegroups.com
err... sorry, but it seems to me that, as big as it is, your test is not giving us the information we need to help you. It seems obvious that you are different implementations in byEmail() and in byPassword(). Surely those implementations differ enough to justify the problem you are seeing, but it is difficult to tell with the information you gave.

Another point is that your tests seem very big (and hard to understand) for what they are testing. There is a lot of scope for simplification...


--
You received this message because you are subscribed to the Google Groups "mockito" group.
To post to this group, send email to moc...@googlegroups.com.
To unsubscribe from this group, send email to mockito+u...@googlegroups.com.

Brice Dutheil

unread,
Jan 16, 2013, 8:14:52 AM1/16/13
to moc...@googlegroups.com
Hi Russell,

This should work. There must be something that make this call not called. Not sure what it is, with the current snippet. Is it expected to pass null to 'walker.byEmail( null );' ?

Also I agree with Eric, you should name your test method with a more meaningful explanation of what is being tested. Soemthing like
read_all_daos_when_walking_accounts_by_email, then you could write other test methos with subtle changes in their name like ..._when_account_not_in_same_group, etc. Adding expectation in the method name is good too.


Cheers,
-- Brice

Malte Finsterwalder

unread,
Jan 16, 2013, 9:03:25 AM1/16/13
to mockito
The test tells you, that the method is not called. Why are you so sure it is called? I don't see any reason to mistrust Mockito here.
Did you debug your test and see the method was called?
Was it called on the mock object?
Did you try to verify the acountDAO.update()-methods first? If they are not called either, then either your code does not call them or you don't pass in the mock to your test object?

And yes, the tests looks much too complicated. Too much setup needed to test the real functionality. Maybe you can better extract the functionality into smaller classes?
And you are testing a lot of data in a single test. Maybe you can split that into multiple tests?

Greetings,
   Malte

Russell Bateman

unread,
Jan 16, 2013, 12:33:24 PM1/16/13
to moc...@googlegroups.com
byEmail() is called with null because there was no date of previous e-mail address change. byEmail() calls the method in question here to get a list of all relevant accounts that need to be walked and annotated for the new e-mail address. The code to do this is identical to that which performs the same for passwords to be synchronized across those accounts. In fact, it is the same code with a parameter to distinguish what's being done.

I don't mistrust Mockito at all, it's just that I single-step through the code and see accountDao.readAllByIdentity( SCHMUCK_EMAIL ) getting called exactly (as nearly as I can tell) as I asked it to and returning exactly what I asked it to return in the original when statement. Later, I get the error saying it was not called.

I thought there might be some diagnostic avenue in Mockito I could use to elucidate why it thinks the method wasn't called instead of having to step back and think about it.

I have so far never had this problem in any of my hundreds of Mockito-based tests: when Mockito says something wasn't called, it has in fact not been called (until this example). This is exactly what I count on since it demonstrates to me that my code is wrong and leads to me fixing it--why I write tests in the first place.

Yes, these two are a little larger than the usual test methods. The granularity is to test the macro functionality of specific code the rest of which is tested in smaller chunks in a different test file.

Maybe as I learn, it will dawn on me how to write smaller tests--a function of understanding what smaller test means, what the boundaries are, etc. My primary objective is to test the walk-federated-accounts manager (business logic) functionality, not learn to write smaller tests. I'm the only one who writes tests in the first place, so it's not as if I live in a test-minded community, let alone one that knows anything about testing using mocks: dawn will come correspondingly slowly as it only can to the blind person walking the path alone.

Thanks for your help. I may have to comment out and add a TODO as a work-around.

Best,

Russ

Brice Dutheil

unread,
Jan 16, 2013, 2:24:45 PM1/16/13
to moc...@googlegroups.com
Maybe the mock instance is not the same. This line is weird for me : 
  EntityTestSupport.setEntityDaoMocks( accountDao, addressDao, paymentDao, callerDao );


Cheers,
-- Brice Dutheil

Reply all
Reply to author
Forward
0 new messages