使用带有真正的Jackrabbit实现的wcm.io AEM Mocks从JSON导入内容

时间:2015-01-19 09:38:10

标签: testing aem jackrabbit jcr sling

我正在尝试使用wcm.io Testing AEM Mocks

编写集成测试

我要测试的代码会在存储库中保存一些数据,因此我想验证在运行测试方法后是否实际存储了正确的内容。

在我之前的测试中,我使用了JCR_MOCK Resource Resolver Type,如下所示:

@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {

    @Rule
    public final AemContext aemContext = new AemContext(ResourceResolverType.JCR_MOCK);

    private MyClass tested;

    @Before
    public void setUp() throws Exception {

        //here, I load an entire page,
        //from which my tested class reads some data
        aemContext.load().json("/jcrdata/myPage.json", "/etc/mystuff/myTool");

        tested = new MyClass(aemContext.resourceResolver());
    }

    @Test
    public void interactWithTheRepository() {

        SomeResult result = tested.interactWithTheRepository();

        //assertions here
    }
}

只要我只想从模拟存储库中读取数据或假装我保存了一些内容,这就可以正常工作。当我真的想验证测试类是否已在存储库中保留某些数据时,问题就开始了。

@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {

    @Rule
    public final AemContext aemContext = new AemContext(ResourceResolverType.JCR_MOCK);

    private MyClass tested;

    @Before
    public void setUp() throws Exception {

        //here, I load an entire page,
        //on which the instance of my tested class later saves some data
        aemContext.load().json("/jcrdata/myPage.json", "/etc/mystuff/myTool");

        tested = new MyClass(aemContext.resourceResolver());
    }

    @Test
    public void storeDataInTheRepository() {

        tested.storeDataInTheRepository();

        //this comes up as null because the JCR_Mock resolver
        //does not use an actual repository and nothing is stored
        Resource result = aemContext.resourceResolver().getResource("/etc/mystuff/myTool/somethingSavedByMyClassInstance");

        //assertions here
    }
}

我相信这可以通过使用实际存储库的JCR_JACKRABBIT Resource Resolver Type来实现。但是,我很难将数据加载到模拟存储库中。我使用JCR_JACKRABBIT JCR_MOCK setUp时,我的NullPointerException方法失败并显示@Rule public final AemContext aemContext = new AemContext(ResourceResolverType.JCR_JACKRABBIT); @Before public void setUp() throws Exception { //This line fails with an NPE aemContext.load().json("/jcrdata/myPage.json", "/etc/mystuff/myTool"); tested = new MyClass(aemContext.resourceResolver()); } (为清晰起见,省略了其他类别的部分)

java.lang.NullPointerException
    at org.apache.sling.resourceresolver.impl.ResourceResolverImpl.create(ResourceResolverImpl.java:1044)
    at org.apache.sling.testing.mock.sling.loader.ContentLoader.createResourceHierarchy(ContentLoader.java:183)
    at org.apache.sling.testing.mock.sling.loader.ContentLoader.createResourceHierarchy(ContentLoader.java:178)
    at org.apache.sling.testing.mock.sling.loader.ContentLoader.json(ContentLoader.java:155)
    at org.apache.sling.testing.mock.sling.loader.ContentLoader.json(ContentLoader.java:120)
    at com.foo.bar.baz.MyClassTest.setUp(MyClassTest.java:35)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    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:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

我调试了代码并注意到它在尝试创建资源层次结构时失败了。

Resource org.apache.sling.testing.mock.sling.loader.ContentLoader.json(String classpathResource, String destPath)

根据文档,Sling Testing应该在尝试从JSON文档加载页面时处理所有父资源的创建:

etc
     

将JSON文件的内容导入存储库。如果缺少,则自动创建父层次结构为nt:unstrucured nodes。

但是,当到达存储库的根目录并且应该在/下创建ContentLoader节点时,createResourceHierarchy的方法ResourceResolver会调用{ {1}}使用以下参数:

resourceResolver.create(null, ResourceUtil.getName("/etc"), props);

其中props是以下结构的简单HashMap{jcr:primaryType=nt:unstructured},导致NullPointerException(由于传递了null个父资源)< / p>

我不确定这是错误还是我做错了什么,the Sling Testing documentation提到了JCR_JACKRABBIT资源解析器类型:

  

要导入Sling内容,您必须完全注册数据所需的所有节点类型

但我不确定如何解释这一点。

我正在使用:

  • io.wcm.testing.aem-mock 1.2.2
  • org.apache.sling.testing.sling-mock-jackrabbit 0.1.0

使用JCR_JACKRABBIT资源解析器实现时,如何从JSON文件加载内容?

2 个答案:

答案 0 :(得分:2)

感谢Thomas' answer我能够向前迈出几步,但仍面临着不同的错误。与此同时,我打开a topic on the wcm.io Developers mailing group来了解是否有可能采用更平易近人的方式实现我的目标。答案分为两部分。第一个描述了为我试图涵盖的特定用例编写测试可以做些什么。后者描述了我实际使用JCR_JACKRABBIT资源解析器类型的结果。

测试写入存储库的类

事实证明,我从JCR_MOCK切换到JCR_JACKRABBIT资源解析器类型的速度太快了。 JCR_MOCK足以满足我的需求,具体如下:

  1. 从类路径上的JSON文件加载内容
  2. 针对模拟存储库执行测试类的方法(该类应该从存储库中读取一些内容并将更多内容存储到其中)
  3. 阅读测试类所写的内容,并断言它是否与预期值匹配
  4. 数据实际上是写入内存存储库。我无法读取它的事实是我自己的错误而不是使用的实现的结果。

    将JSON加载到JCR_JACKRABBIT支持的AemContext

    我设法在Thomas' answer的建议下走得很远,但我没有成功地完成这项实施工作。这就是我的所作所为:

    我在setUp方法中添加了以下行:

    Session session = aemContext.resourceResolver().adaptTo(Session.class); 
    RepositoryUtil.registerNodeType(session, getClass().getResourceAsStream("/nodetypes/types.cnd")); 
    

    aemContext.load().json("/jcrdata/myPage.json", "/etc/mystuff/myTool");

    之前

    types.cnd是我的类路径上的一个文件,其中包含在我的AEM实例上的CRX存储库中找到的节点类型定义。

    这使我摆脱了NPE,但由于某种原因,cq:Pagecq:PageContent节点类型无法识别。如果加载的JSON中存在这些类型中的任何一个类型的节点,则会在调用PersistenceException时抛出aemContext.load().json("/jcrdata/myPage.json", "/etc/mystuff/myTool");

    问题似乎是cq:Pagecq:PageContent节点类型仍然无法找到,尽管我在types.cnd文件中明确添加它们。我从docs.adobe.com中获取了这两种类型的定义,并确保包含这些定义中使用的名称空间前缀。

    这是我在我的内容JSON中有一个cq:Page时出现的示例堆栈跟踪:

    java.lang.RuntimeException: org.apache.sling.api.resource.PersistenceException: Unable to create node at /etc/foo/bar/baz
        at org.apache.sling.testing.mock.sling.loader.ContentLoader.json(ContentLoader.java:167)
        at org.apache.sling.testing.mock.sling.loader.ContentLoader.json(ContentLoader.java:120)
        at com.foo.bar.baz.MyClassTest.setUp(MyClassTest.java:42)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:601)
        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.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
        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:50)
        at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
    Caused by: org.apache.sling.api.resource.PersistenceException: Unable to create node at /etc/foo/bar/baz
        at org.apache.sling.jcr.resource.internal.helper.jcr.JcrResourceProvider.create(JcrResourceProvider.java:473)
        at org.apache.sling.resourceresolver.impl.tree.ResourceProviderEntry.create(ResourceProviderEntry.java:479)
        at org.apache.sling.resourceresolver.impl.ResourceResolverImpl.create(ResourceResolverImpl.java:1053)
        at org.apache.sling.testing.mock.sling.loader.ContentLoader.createResource(ContentLoader.java:217)
        at org.apache.sling.testing.mock.sling.loader.ContentLoader.json(ContentLoader.java:163)
        ... 30 more
    Caused by: javax.jcr.nodetype.NoSuchNodeTypeException: {http://www.day.com/jcr/cq/1.0}Page
        at org.apache.jackrabbit.core.nodetype.NodeTypeRegistry.getEffectiveNodeType(NodeTypeRegistry.java:1024)
        at org.apache.jackrabbit.core.nodetype.NodeTypeRegistry.getEffectiveNodeType(NodeTypeRegistry.java:487)
        at org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl.getNodeType(NodeTypeManagerImpl.java:177)
        at org.apache.jackrabbit.core.NodeImpl.addNode(NodeImpl.java:1240)
        at org.apache.jackrabbit.core.session.AddNodeOperation.perform(AddNodeOperation.java:111)
        at org.apache.jackrabbit.core.session.AddNodeOperation.perform(AddNodeOperation.java:37)
        at org.apache.jackrabbit.core.session.SessionState.perform(SessionState.java:200)
        at org.apache.jackrabbit.core.ItemImpl.perform(ItemImpl.java:91)
        at org.apache.jackrabbit.core.NodeImpl.addNodeWithUuid(NodeImpl.java:1769)
        at org.apache.jackrabbit.core.NodeImpl.addNode(NodeImpl.java:1729)
        at org.apache.sling.jcr.resource.internal.helper.jcr.JcrResourceProvider.create(JcrResourceProvider.java:435)
        ... 34 more
    

    但是,只要我用cq:Page替换所有cq:PageContentnt:unstructured类型,我就可以成功导入内容 这允许我对存储库执行我的代码并读取我测试的类在那里写的内容但是我有点担心我的测试内容具有与其真实对应物不同的节点类型的事实可能在某些情况下影响测试结果。

    JCR_JACKRABBIT还需要创建一个Derby数据库,在测试执行之间不会清除它。

    总而言之,JCR_JACKRABBIT引入了一些问题,在我的具体情况下,JCR_MOCK没有任何优势。我被建议不要使用它,除非我真的需要模拟JCR_MOCK不支持的高级功能,例如事件或版本控制。

    引用Stefan Seifert's comment on the wcm.io Developers mailing group

      

    仅当您需要JCR_MOCK不支持的特殊功能时才使用JCR_JACKRABBIT,例如:事件,版本控制等等但是只有这样,它才是最重量级和最不顺畅的选择,并且目前使用不多。我们对吊索中吊索模拟长耳机的当前行李箱中的这种集成进行了一些小的改进,尤其是承认内容加载器和无法导入的特殊属性,但尚未发布。

答案 1 :(得分:1)

它告诉您,您的实现不知道结构中的不同节点类型及其约束,并且无法创建这样的节点。

您是否尝试在类路径中放置nodetype定义(nodetype.cnd)(只需将其放入src / test / resources目录中)并使用RepositoryUtil加载它?

RepositoryUtil.registerNodeType(session, getClass().getResourceAsStream("nodetypes.cnd"));