title: How to spy on injected singleton?
body: <p>I have a validation method in a model class that gets called from code that I don't have control over. This validation method has parameters that come from dependency injection. One of these parameters is a singleton (<code>@Singleton</code>) class.</p>
  
  <pre><code>@Singleton
  public class ObjValidation {
      @Inject
      public ObjValidation() {
          objsCache = new HashSet&lt;&gt;();
      }
  
      public boolean exists(String obj) {
          return objsCache.contains(obj) || lookupObj(obj);
      }
  
      ...
  }
  </code></pre>
  
  <p>As you can see this singleton does perform a lookup on a database if the object isn't contained in the cache. While testing this database isn't there and should not be tested. Therefore I'm trying to mock the <code>exists()</code> method to return true without being run.</p>
  
  <p>My first thought was, since this is a singleton, if I would inject the singleton into my test case before running it, I would create the singleton instance therefore could <code>spy</code> on it.</p>
  
  <pre><code>ObjValidation objValidation = spy(app.injector().instanceOf(ObjValidation.class));
  doReturn(true).when(objValidation).exists(any());
  </code></pre>
  
  <p>But yes, <code>spy</code> only returns a copy and therefore doesn't spy on the instantiated singleton. I would need to replace the singleton instance with the <code>spy</code> copy to make it work this way.</p>
  
  <p>How can I do this?</p>
  
  <hr>
  
  <p>Further explanation of the test case:</p>
  
  <p>In my test (method under test is <code>register()</code>) I bind a scala.html view form to a model class via the build in functionality of the play framework.</p>
  
  <pre><code>public Result register() throws ResultMessageException {
      ...
      Form&lt;Registration&gt; filledRegistrationForm = this.formFactory.form(Registration.class).bindFromRequest();
      ...
  }
  </code></pre>
  
  <p>The model has a validation method that has parameters that get injected as described in the play documentation: <a href="https://www.playframework.com/documentation/2.6.x/JavaForms#Custom-class-level-constraints-with-DI-support" rel="nofollow noreferrer">https://www.playframework.com/documentation/2.6.x/JavaForms#Custom-class-level-constraints-with-DI-support</a></p>
  
  <pre><code>@ValidateWithDI
  public class Registration implements ValidatableWithDI&lt;ValidationError&gt; {
  
      @Required
      private String obj;
  
      @Override
      public ValidationError validate(ObjValidation objValidation) {
          if (!objValidation.exists(obj)) {
              return new ValidationError("obj");
          }
          return null;
      }
  }
  </code></pre>
  
  <p>This validation method gets called by the framework while binding the form.</p>