4

I'm trying to setup mocks for mongodb in my java code, and I'm getting the following exception:

org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
DBCursor$$EnhancerByMockitoWithCGLIB$$fc4f0e22 cannot be returned by getOptions()
getOptions() should return int

The line of code that generates this is:

when(col.find(query)).thenReturn(cursor);

Where col is a mocked DBCollection, query is a mocked DBObject, and cursor is a mocked DBCursor.

I've found the following very vague but probably relevant problem description:

http://osdir.com/ml/mongodb-user/2010-08/msg02102.html

Kevin
  • 24,871
  • 19
  • 102
  • 158

1 Answers1

4

Just found the issue, the find(DBObject obj) method is final in DBCollection:

http://grepcode.com/file/repo1.maven.org/maven2/org.mongodb/mongo-java-driver/2.1/com/mongodb/DBCollection.java

PowerMock ultimately solved my issue since it allows mocking final methods.

Kevin
  • 24,871
  • 19
  • 102
  • 158
  • There's a saying : "Don't mock type you don't own!" – bric3 Nov 05 '11 at 01:54
  • 2
    @Brice: Actually I'm pretty sure you're supposed to mock the types you don't own. So I don't see your point. – Kevin Nov 05 '11 at 04:10
  • Well, it is wrong for several reasons (however there might be exceptions). The type you don't own have their own behavior, don't try to mock that. Make instead an integration type that uses the real types. Read this [post](http://www.davesquared.net/2011/04/dont-mock-types-you-dont-own.html), it will explains better and more thorougly than this comment why I'm saying _Don't mock type you don't own!_ – bric3 Nov 05 '11 at 10:03
  • 2
    Direct calls to external services create slow and unreliable unit tests, which is why mocks exist. Integration tests are necessary no doubt but are separate from unit tests. – Kevin Nov 06 '11 at 05:11
  • Don't MongoDB tests fall in the integration test category? ;) If all your tests need to call external services you might have a design issue or facing "legacy design". If you really need to mock external systems, then wrap them in types you actually own, these wrappers will then be tested as integration tests. Other object can be tested as usual with mocks if necessary. And by the way, _Don't mock type you don't own_ is one of the mockito's guideline since a very long time. – bric3 Nov 06 '11 at 14:34
  • I did wrap the mongo calls but there is still some business logic in that wrapper code that I do need to unit test. That's why I'm mocking mongo. – Kevin Nov 06 '11 at 14:55
  • Wrapper + Business logic, in the same object, it seems wrong to me. Both have nothing to do at the same place, try to revise your design with sepration of concerns in mind. The business logic might be moved to callbacks, strategies, or whatever, this way you can only mock your code. – bric3 Nov 06 '11 at 15:46
  • Brice: I've read your article but I disagree with the premise that external services should not be mocked. I agree that if you're hell bent on separating business logic from mongo calls your suggestion is correct. The problem is that the mongo wrapper at that point only exists so I can say that I'm not mocking external calls; it provides no other value whatsoever. Maybe you mean I should make it a dao so that I can drop in a different implementation later without changing the service layer, but that just isn't going to happen. So a dao layer just adds complexity/verbosity but no real benefit. – Kevin Nov 06 '11 at 16:00
  • It's your call, but many people agree with that axiom, there's a question [here on that subject](http://stackoverflow.com/questions/1906344/should-you-only-mock-types-you-own). On the matter of separating business from the access layer, I'm actually not fond at all of _DAOs_ or _Data Access Services_, nevertheless a technical inderection between you business code and a pure generic data layer is not a bad idea in itself. Especially in theses days where there's a lot of innovation around NoSQL. I'm not saying that you should add DAOs, but rather to separate the different concerns of your code. – bric3 Nov 07 '11 at 09:27
  • yes I read that last night. there are at least a few people (including accepted answer) that think that the rationale given in Mark's post makes sense for hibernate and EntityManager but may or may not apply to other cases. I personally don't think it applies to my case. Anyway thanks for your inputs since I wasn't aware of that philosophy. – Kevin Nov 07 '11 at 14:57
  • OK nice to know that it helped out :) I'd like to recommand another blog post by the way, James Carr has listed some test/TDD anti-patterns, it's a good reading : http://blog.james-carr.org/2006/11/03/tdd-anti-patterns/ – bric3 Nov 08 '11 at 10:43
  • Thanks for following up with your solution -- this was driving me batty! – Erik Dietrich Apr 10 '12 at 05:44