title: Sling model unit tests: mock currentPage in SlingHttpServletRequest
body: <p>I am having some trouble testing a Sling model: the currentPage is not getting injected for some reason.</p>
  
  <p>My Sling model looks like this:</p>
  
  <pre><code>@Model( adaptables = { SlingHttpServletRequest.class, Resource.class }, 
      resourceType = MyModel.RESOURCE_TYPE)
  public class MyModel {
  
     public static final String RESOURCE_TYPE = "myproject/components/renderer";
  
     @Inject
     private Page currentPage;
  
     // Model methods, etc.
  
  }
  </code></pre>
  
  <p>I writing some JUnit tests for it, like so:</p>
  
  <pre><code>@RunWith(MockitoJUnitRunner.class)
  public class MyModelTest {
  
    @Rule
    public final AemContext context = new AemContext();
  
    @Mock
    private SlingHttpServletRequest request;
  
    private static final String RESOURCE_PATH = "/content/myproject/jcr:content/myModel";
    private static final String PAGE_PATH = "/content/common/page";
  
    private MyModel myModel;
  
    @Before
    public final void setUp() throws Exception {
      context.load().json("/models/MyModel.json",RESOURCE_PATH);
      context.load().json("/common-page.json", PAGE_PATH);
  
      Resource pageResource = context.resourceResolver().getResource(PAGE_PATH);
      Page page = pageResource.adaptTo(Page.class);
  
      context.currentPage(page);
      context.addModelsForClasses(MyModel.class);
      when(request.getResource()).thenReturn(context.resourceResolver().getResource(RESOURCE_PATH));
      myModel = request.getResource().adaptTo(MyModel.class);
    }
  
    @Test
    public void simpleLoadTest(){
      assertNotNull(myModel);
    }   
  }
  </code></pre>
  
  <p>And this is is the error I am getting:</p>
  
  <pre><code>   [main] WARN org.apache.sling.models.impl.ModelAdapterFactory - Could not adapt to model
    org.apache.sling.models.factory.MissingElementsException: Could not inject all required fields into class com.myproject.common.core.models.MyModel
     at org.apache.sling.models.impl.ModelAdapterFactory.createObject(ModelAdapterFactory.java:558)
     at org.apache.sling.models.impl.ModelAdapterFactory.internalCreateModel(ModelAdapterFactory.java:319)
     at org.apache.sling.models.impl.ModelAdapterFactory.getAdapter(ModelAdapterFactory.java:195)
     at org.apache.sling.testing.mock.sling.MockAdapterManagerImpl.getAdapter(MockAdapterManagerImpl.java:146)
     at org.apache.sling.testing.mock.sling.ThreadsafeMockAdapterManagerWrapper.getAdapter(ThreadsafeMockAdapterManagerWrapper.java:46)
     at org.apache.sling.api.adapter.SlingAdaptable.adaptTo(SlingAdaptable.java:104)
     at org.apache.sling.testing.resourceresolver.MockResource.adaptTo(MockResource.java:110)
     at uk.co.restaurants.common.core.models.MyModelTest.setUp(MyModelTest.java:44)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
     at java.lang.reflect.Method.invoke(Method.java:498)
     at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
     at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
     at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
     at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
     at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:48)
     at org.junit.rules.RunRules.evaluate(RunRules.java:20)
     at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
     at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
     at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
     at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
     at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
     at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
     at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
     at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
     at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
     at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
     at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
     Suppressed: org.apache.sling.models.factory.MissingElementException: Could not inject private com.day.cq.wcm.api.Page com.myproject.common.core.models.MyModel.currentPage
         at org.apache.sling.models.impl.ModelAdapterFactory.createObject(ModelAdapterFactory.java:562)
         ... 34 more
     Caused by: org.apache.sling.models.factory.ModelClassException: No injector returned a non-null value!
         at org.apache.sling.models.impl.ModelAdapterFactory.injectElement(ModelAdapterFactory.java:482)
         at org.apache.sling.models.impl.ModelAdapterFactory.createObject(ModelAdapterFactory.java:560)
         ... 34 more
  </code></pre>
  
  <p>For some other Sling models tests the injects work nicely, although for currentPage I am not sure how to proceed.
  I could not find documentation either about mocking the currentPage object in the Sling model.</p>
  
  <p>Any help would be greatly appreciated.</p>
  
  <hr>
  
  <h2>UPDATE</h2>
  
  <p>The below comments helped understand better how this test should be looking.
  I did some changes, my test is still failing though. Now the classes look like so:</p>
  
  <pre><code>@RunWith(MockitoJUnitRunner.class)
  public class MyModelTest {
  
    @Rule
    public final AemContext context = new AemContext();
  
    @Mock
    private SlingHttpServletRequest request;
  
    @Mock
    AemObjectAnnotationProcessorFactory factory;
  
    @InjectMocks
    AemObjectInjector aemObjectInjector;
  
    private static final String RESOURCE_PATH = "/content/myproject/jcr:content/mymodel";
    private static final String PAGE_PATH = "/content/common/page";
  
    private MyModel mymodel;
  
    @Before
    public final void setUp() throws Exception {
      context.load().json("/common-page.json", PAGE_PATH);
      Resource pageResource = context.resourceResolver().getResource(PAGE_PATH);
      Page page = pageResource.adaptTo(Page.class);
      context.currentPage(page);
  
      context.load().json("/models/MyModel.json",RESOURCE_PATH);
      context.request().setServletPath(RESOURCE_PATH);
      context.registerInjectActivateService(factory);
      context.registerService(AemObjectInjector.class, aemObjectInjector);            
  
      Mockito.when(request.getResource())
        .thenReturn(context.resourceResolver().getResource(RESOURCE_PATH));
      Resource resource = request.getResource();
      mymodel = resource.adaptTo(MyModel.class);
    }
  
    @Test
    public void simpleLoadTest(){
        assertNotNull(mymodel);
    }  
  </code></pre>
  
  <p>}</p>
  
  <p>And the updated model with the specific injector:</p>
  
  <pre><code>@Model(
     adaptables = { SlingHttpServletRequest.class }, 
     resourceType = MyModel.RESOURCE_TYPE)
  public class MyModel {
  
    public static final String RESOURCE_TYPE = "myproject/components/renderer";
  
    @AemObject
    private Page currentPage;
  
    // Model methods, etc.
  
  }
  </code></pre>
  
  <p>The setUp() method does not throw any exception, no warnings whatsoever.
  The variable mymodel is null so I am still missing things here.</p>
  
  <hr>
  
  <h2>UPDATE 2</h2>
  
  <p>I pushed the code to Github, you can find the project in the following URL 
  <a href="https://github.com/josebercianowhitbread/myproject" rel="nofollow noreferrer">https://github.com/josebercianowhitbread/myproject</a></p>
  
  <p>Notes:</p>
  
  <p>-It was tested in AEM 6.3</p>
  
  <p>-To deploy the project, as usual: mvn clean install -PautoInstallPackage</p>
  
  <p>-The project adds some sample pages to make sure the Sling model works as expected</p>
  
  <p>-The Sling model functionality is quite trivial: it goes up the content tree until it finds the parent node with a "isRootPage" property set to true.</p>
  
  <p>Any questions you might have let me know.</p>
  
  <p>Thanks in advance for any help provided.</p>
  
  <hr>
  
  <h2>UPDATE 3</h2>
  
  <p>Justin Edelson kindly corrected and provided the code of the test. Big thanks to him and also Ahmed Musallam who has chased this post until he made sure everything was working fine :)</p>
  
  <p>The 2 main issues with my initial code were:
  I was trying to mock the Slick request, but should have used the request from the AemContext instead. 
  The model was not registered.</p>
  
  <pre><code>public class MyModelTest {
  
     @Rule
     public final AemContext context = new AemContext();
  
     private MockSlingHttpServletRequest request;
  
     AemObjectAnnotationProcessorFactory factory = new AemObjectAnnotationProcessorFactory();
  
     AemObjectInjector aemObjectInjector = new AemObjectInjector();
  
     private static final String RESOURCE_PATH = "/content/parent-page/jcr:content/content/renderer";
     private static final String PAGE_PATH = "/content/parent-page";
  
     private MyModel mymodel;
  
     @Before
     public final void setUp() throws Exception {
         request = context.request();
         context.addModelsForClasses(MyModel.class);
         context.load().json("/pages/common-page.json", PAGE_PATH);
         Resource pageResource = 
         context.resourceResolver().getResource(PAGE_PATH);
  
         Page page = pageResource.adaptTo(Page.class);
         context.currentPage(page);
  
         context.load().json("/models/MyModel.json", RESOURCE_PATH);
         context.registerInjectActivateService(factory);
         context.registerService(AemObjectInjector.class, aemObjectInjector);
  
  
         request.setResource(context.resourceResolver()
           .getResource(RESOURCE_PATH));
         mymodel = request.adaptTo(MyModel.class);
     }
  
     @Test
     public void simpleLoadTest() {
         assertNotNull(mymodel);
     }
  </code></pre>
  
  <p>}</p>