-1

I have a class that I want to test, and also mock a specific method. I've created a spy as follows:

CredentialsService partialMock = spy(CredentialsService.class);

And call in my test to a method I want to test: partialMock.process(client, id, url, null, userDetails);

In real method:

@Autowired private EncryptionService encryptionService; My rest fails on NullPointerException, because one of the autowires of the class is NULL. In this line:

Credential credentials = new Credential(id, encryptionService, tokenResponseParams.getAccessToken(), tokenResponseParams.getRefreshToken(), tokenResponseParams.getExpiresIn());
 

encryptionService is null and one of the operation in creating the Credential class fail on this.

Any idea why my spy does not keep the real instance of encryptionService as a bean, and how I can fix it?

TheUnreal
  • 23,434
  • 46
  • 157
  • 277

1 Answers1

1

You are creating a spy using only a class parameter in the spy() method, so Mockito does not know about any object that should be injected into the created spy object.

To inject the missing dependency you can pick one of three approaches (one without modification of the actual code). For the sake of simplification in the example I've stripped the objects as complete code was not provided.


Let's assume field injection first (here's more on why it's discouraged to use field injection):

class EncryptionService {

    void encrypt() {
        System.out.println("Encrypted!");
    }
}

class CredentialsService {

    EncryptionService encryptionService;

    void process() {
        encryptionService.encrypt();
    }
}

Annotations

@Mock // or @Spy, or actual object
EncryptionService encryptionService;
@Spy
@InjectMocks // this tells Mockito to inject dependencies
CredentialsService credentialsService;

@BeforeEach
void setUp() {
    // here the injection actually happens
    // openMocks() in more recent versions of Mockito
    MockitoAnnotations.initMocks(this);
}

@Test
void annotationInjection() {
    credentialsService.process();
}

For both approaches below we will need the dependencies to be injected in a constructor, so CredentialsService looks like this:

class CredentialsService {

    EncryptionService encryptionService;

    CredentialsService(EncryptionService encryptionService) {
        this.encryptionService = encryptionService;
    }

    void process() {
        encryptionService.encrypt();
    }
}

Mock settings

@Test
void mockWithSettings() {
    var credentialsService = mock(CredentialsService.class, withSettings()
            // EncryptionService could be also a mock or a spy
            .useConstructor(new EncryptionService())
            // actually acts like a spy thanks to the below setting
            .defaultAnswer(CALLS_REAL_METHODS));
    
    credentialsService.process();
}

(read more in the Mockito documentation)


Spy on an object

@Test
void spyOnObject() {
    var encryptionService = mock(EncryptionService.class);
    var credentialsService = spy(new CredentialsService(encryptionService));

    credentialsService.process();
}

I'm usually using the first or last approach from the ones above (but the first one with dependencies injected by constructor - it works as well).

Jonasz
  • 1,617
  • 1
  • 13
  • 19