hj690
hj690

Reputation: 25

How do I mock a class with private fields?

I'm trying to test a singleton class with Mockito, something like this:

  public class Single {
     private ID id;
     private Single(){}  //private constructor 
     public static Single getSingle(){ // ***code to get instance*** }

     // method I want to test
     public String getName(){ 
        String name = id.getRawName(); // need field id here
        ** additional operations on name ** // code need to be tested
        return name;
     }

  }

I tried to mock this class and set field "id" with reflection, like this:

Single sg = Mockito.mock(Sincle.class);
Field myID = sg.getClass().getDeclaredField("id"); // fails here
myID.setAccessible(true);
myID.set(sg, <ID instance>);

However it fails at getDeclaredField() method, with exception

java.lang.NoSuchFieldException: id

I guess it's because id field is null in instance sg.

So I'm wondering if there's anything I can do to test this method without modify the original class?

Upvotes: 1

Views: 6311

Answers (2)

durron597
durron597

Reputation: 32323

A mock is not a real object. You can't set a declared field of a mock because it doesn't exist1!

When you are writing tests, you generally want to mock all the classes that are not:

Therefore, the thing you really want to be mocking is ExternalCall, which you don't really explain how it works in your question. However, if it's a static method, you need to use PowerMock. See: Mocking static methods with Mockito

Note that your error is NoSuchFieldException, because you don't actually have a real instance. It's not because:

I guess it's because id field is null in instance sg.

It's because the field actually doesn't exist1 in the mockito generated subclass, not because it's null.

1: It does exist in mock's superclass (in this case, Single), but its value is captured by the mocking behavior and is ignored unless you use it as a partial mock. However, this is a technical detail and not relevant to the proper using of Mockito.

Upvotes: 1

Keith
Keith

Reputation: 3151

...anything I can do to test this method without modify the original class?

Yes, there is. Use Mockito for its bread-and-butter purposes:

when(sg.getId()).thenReturn("123")

Upvotes: 0

Related Questions