25

I have a simple class Foo to be mocked:

public class Foo {
   private String name;
   public Foo() {
   }
   public Foo(String name) {
     this.name = name;
   }

   public void setName(String name) {
     this.name = name;
   }
   public String getName() {
     return name;
   }
}

In my unit test code, I mock it by using Mockito.

Foo mockedFoo = Mockito.mock(Foo.class);
mockedFoo.setName("test");
// name is null
String name = mockedFoo.getName();

I set name in mocked object, but when I call getter to get the name it returns null.

Is it a Mockito specific issue or is it an convention that mocked object can't set value? Why is that? What is happening underneath with mocked object?

Leem.fin
  • 40,781
  • 83
  • 202
  • 354
  • 6
    `when(mockedFoo.getName()).thenReturn("test");`. – Tom Dec 10 '15 at 15:02
  • @Tom , I know this, but I want to know why I can not directly set value on mocked object, I am not asking how to stub function return. – Leem.fin Dec 10 '15 at 15:03
  • Because it is a mocked object, and it's purpose is not to store stuff. Create your own instance if you want to do that. – Tom Dec 10 '15 at 15:04
  • @ Tom, so now you answered something I expected, so, it is a "convention" that mocked object looses the functions designed in the class. – Leem.fin Dec 10 '15 at 15:05
  • 1
    Convention? I'd call it definition. – Manu Dec 10 '15 at 15:09
  • Yes, a mock just provides the same API, but no implementations. And that is why you use a mock. If you test class `A` (in a unit test), which uses `B` to store stuff in a file, then you want to mock `B`, so it doesn't actually perform "file stuff", because your main purpose is to test `A`, not `B`. – Tom Dec 10 '15 at 15:09
  • @Manu , that's why I added quotation marks around the word "convention". I know there will be someone argue about the word I am using. – Leem.fin Dec 10 '15 at 15:10
  • @ Tom, thanks for the clearer comment answered my question. – Leem.fin Dec 10 '15 at 15:13
  • @ Tom, I prefer your explanation, I feel it gives a knowledge about all mocked object in general, could you please make an answer I will accept it. – Leem.fin Dec 10 '15 at 15:18
  • @Leem.fin: But you should understand that this is specific to particular mocking frameworks. It's possible for a mocking framework to simulate trivial properties, and indeed some in .NET do exactly that. It looks like Mockito doesn't, but I wouldn't want to extend that to be too general. – Jon Skeet Dec 10 '15 at 15:22
  • @Leem.fin: Jons answer is already a good one, so it is a very good candidate to be accepted :). – Tom Dec 10 '15 at 15:22

6 Answers6

42

Well yes - the actual code of Foo doesn't matter, because you're mocking it... and Mockito doesn't know there's meant to be a relationship between setName and getName. It doesn't assume that it should store the argument to setName and return it when getName is called... it could do that, but it doesn't as far as I'm aware. The mock provided by Mockito just allows you to specify what happens when methods are called on it, and check what was called later on. Instead of calling setName, you could mock a call to getName() and specify what it should return...

... or you could just use Foo directly instead of mocking it. Don't think you have to mock everything in your tests. Just mock (or fake) things that are awkward when you're using the real class, e.g. because it uses the file system or network.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 3
    Indeed; from my experience, too often people mock "value-object" classes when they shouldn't. One thing I considered in the past was if it would be a good idea for a mocking library to detect such classes when a test attempts to mock them, and then throw an "invalid mocking" exception. Might be a good "opt-in" feature to add (and not too hard to implement). – Rogério Dec 11 '15 at 18:04
  • but, we cannot mock a final method. How do we do in that case – Sree Feb 04 '21 at 18:38
  • @Sree: That's not what this question is about - I suggest you ask a new question if you can't find one which *does* match what you're asking. (I strongly suspect there are such questions though.) – Jon Skeet Feb 04 '21 at 20:01
20

By default mockito has no behavior, on any methods in the mocked object.

You should do something like this:

Foo mockedFoo = Mockito.mock(Foo.class);
when(mockedFoo.getName()).thenReturn("someName");
String name = mockedFoo.getName();

edit: as mentioned by Jon Skeet, you should not need to mock things that can just be tested in a normal fashion.

Martin Hansen
  • 2,033
  • 1
  • 18
  • 34
2

I think, its better to understand as what Mockito does to your argument class and what kind of object it returns by referring to source code , Mockito Source

General understanding is that a mocked object is a fake object ( of same type as argument provided to mock() method ) with no real method implementations.So basically, nothing happens in real life for a method call on mocked object - and that is the very purpose of creating a mocked object ( that we don't wish to call real methods ) , isn't it?

We mock DAO layer, LDAP layer or other service dependencies because we don't want to invoke calls to actual DB or services. If we want real calls to happen, we would not create mocked objects.

Understanding to have something real have happened after calling mockedFoo.setName("test"); OR mockedFoo.getName(); is incorrect - Nothing happens after you call a method on a mocked object and that is the purpose of mocked object which it is fulfilling.

Sabir Khan
  • 9,826
  • 7
  • 45
  • 98
2

To solve your problem of knowing whether the setName() method was called in your code with the specified value use the Mockito verify method.

For example:

verify(mockedFoo, times(1)).setName("test");

Will verify that the mockedFoo.setName() method with the String parameter "test" was called exactly once in the code under test.

David George
  • 3,693
  • 1
  • 18
  • 22
1

You need to call real methods on the mocked objects. use @Spy

abhihello123
  • 1,668
  • 1
  • 22
  • 38
0

Somewhat this kind of approach is to used. I have written for EasyMock but with Mockito it can also be used as same.

String nameMock = createNiceMock(String.class);
Foo MockedFoo = new Foo();
Foo.setName(nameMock);

EasyMock.expect(Foo.getName()).andReturn(nameMock);
Vishal Sheth
  • 163
  • 1
  • 7