Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Added rating macro
Wiki Markup
{rate}
h2. Introduction

Magnolia uses JUnit 4 tests and Mockito 

Introduction

...

(new) for creating unit tests. Before we were using EasyMock for dynamic mocks.

...


Independently from that make sure your tests match our [conventions|http://wiki.magnolia-cms.com/display/DEV/Unit-Test+style]. Additional information on how to best migrate JUnit3-style tests to JUnit4 can be found [here

...

Mockito

Mockito is a more recent mocking library. We'll not convert existing EasyMock-Tests as this would be to big an effort. Instead we set up the following rules:

  • all new tests requiring dynamic mocks use Mockito
  • whenever you touch (fix, adapt, complete) an existing test that's using EasyMock: convert it to Mockito

Setting up for Magnolia testing

There are some handy classes available when creating tests for your Magnolia functionality. To get them working in your Maven project, add the following dependencies to your project descriptor.

Code Block
titlepom.xml
|http://wiki.magnolia-cms.com/display/DEV/Converting+JUnit3+tests+to+4-style].

h2. [Mockito|http://code.google.com/p/mockito/]

Mockito is a more recent mocking library. We'll not convert existing EasyMock-Tests as this would be to big an effort. Instead we set up the following rules:
* all new tests requiring dynamic mocks use Mockito
* whenever you touch (fix, adapt, complete) an existing test that's using EasyMock: convert it to Mockito

h2. Setting up for Magnolia testing

There are some handy classes available when creating tests for your Magnolia functionality. To get them working in your Maven project, add the following dependencies to your project descriptor.

{code:title=pom.xml}    ...

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.4</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-core</artifactId>
      <version>1.8.5</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>info.magnolia</groupId>
      <artifactId>magnolia-core</artifactId>
      <version>${magnoliaVersion}</version>
      <type>test-jar</type>
      <scope>test</scope>
    </dependency>

    ...

Magnolia Mocking overview

For testing basic functionality that does depend on itself there is no need to use mock objects we can just test that method functionality straight away, but usually we need to test objects that depend on other objects and there is where we use this mock objects, beware that they can just return what you want but the code behind won't be executed.

Imagine you need to test something that depends on a repository, well you can 'mock' a repository and it's content without having to create the repository itself. You can extend your test class from MgnlTestCase that will setup the basic environment for you and then use something like:

Code Block

{code}
h2. Magnolia Mocking overview

For testing basic functionality that does depend on itself there is no need to use mock objects we can just test that method functionality straight away, but usually we need to test objects that depend on other objects and there is where we use this mock objects, beware that they can just return what you want but the code behind won't be executed.

Imagine you need to test something that depends on a repository, well you can 'mock' a repository and it's content without having to create the repository itself. You can extend your test class from MgnlTestCase that will setup the basic environment for you and then use something like:
{code}
HierarchyManager hm = MockUtil.createAndSetHierarchyManager(REPOSITORY, CONTENT);
{code}
By doing this you can access to the nodes of you 'fake' repositoy as if it where real. But if you really need to use a real repository you can extend from RepositoryTestCase and use the methods declared in it.

...



h4. Useful classes included in magnolia-core for building tests:

...



Here are some of the clases we have for Magnolia testing, you can find more classes in package info.magnolia.

...

  • MgnlTestCase - Sets up a basic environment for the test, loads beans and modules properties and initializes a mock context as the local context.
  • MockUtil - You can create mock objects and using createHierarchyManager you can build mock content based on a property file. The content can be force to be ordered and it allows you to create nodes, content, properties...
  • MockContent - emulates a Content object used by MockUtil
  • MockConext - emulates a context where you can set a mocked hierarchy manager
  • RepositoryTestCase - Can be used to test on a real repository. It will initialize and delete it when finished.
  • FactoryUtil - Class to allow various kinds of classes instantiations. Includes methods to convert content to beans.
Code Block
test&nbsp;
* MgnlTestCase - Sets up a basic environment for the test, loads beans and modules properties and initializes a mock context as the local context.

* MockUtil - You can create mock objects and using createHierarchyManager you can build mock content based on a property file. The content can be force to be ordered and it allows you to create nodes, content, properties...

* MockContent - emulates a Content object used by MockUtil
* MockConext - emulates a context where you can set a mocked hierarchy manager

* RepositoryTestCase - Can be used to test on a real repository. It will initialize and delete it when finished.

* FactoryUtil - Class to allow various kinds of classes instantiations. Includes methods to convert content to beans.

{code}
final SystemContext sysCtx = createStrictMock(SystemContext.class);

        sysCtx.setLocale(Locale.ENGLISH);

        FactoryUtil.setInstance(SystemContext.class, sysCtx);
{code}
What this example does is to use the EasyMock method createStrictMock that creates an instance of the SystemContext inteface meaning that it creates a mock object that implements this interface checking the order of method calls. It sets the property Locale to this new context and then uses the FactoryUtil class to register the new instance which will be returned by getSingleton()

...

Magnolia Mock Objects

Content API Mocks

...


\\

h2. Magnolia Mock Objects 

h3. Content API Mocks

The customized mock objects that we provide to be able to setup an environment for Magnolia tests can be found in package info.magnolia.test.mock.

...



When creating a mock hierarchy manager you can either initialize it from a properties file:

...


{code
:title
=sample.properties
}main@type = mgnl:content
main@uuid = 1

main/uuidLink@type = mgnl:contentNode
main/uuidLink@uuid = 2
main/uuidLink.MetaData.mgnl\:template = someParagraphName
main/uuidLink.MetaData.mgnl\:authorid = superuser
main/uuidLink.MetaData.mgnl\:activatorid = superuser
main/uuidLink.MetaData.mgnl\:title = myTitle
main/uuidLink.link1 = 3

main/linkTarget@type = mgnl:content
main/linkTarget@uuid = 3
main/linkTarget.prop1 = sub2value1
main/linkTarget.prop2 = sub2value2
main/linkTarget.prop3 = boolean:false

main/content@type = mgnl:contentNode
main/content@uuid = 4
main/content.value = Content Value
Code Block
title
{code}
{code:title=CreateMockContentFromPropertiesFile.java
}HierarchyManager hm = MockUtil.createAndSetHierarchyManager(ContentRepository.USERS, getClass().getResourceAsStream("sample.properties"));
{code}
or you can create a variable with the data or pass it to the method call directly:

...

Code Block
title

\\
{code:title=CreateMockContentFromString.java
}final String CONTENT = StringUtils.join(Arrays.asList(
    "main/content@type=mgnl:contentNode",
    "main/content@uuid=4",
    "main/content.value=Content Value"
    ), "\n");

HierarchyManager hm = MockUtil.createAndSetHierarchyManager(ContentRepository.USERS, CONTENT);
{code}
You may also directly instantiate a MockContent and then add the child Contents and or NodeData's as required

...


{code
:title
=CreateMockContentUsingAPI.java
}
MockContent page = new MockContent("page");
page.createContent("subpage", ItemType.CONTENT);
page.setNodeData("stringProperty", "HelloWorld");

JCR Mocks

...

{code}


h3. JCR Mocks
Since Magnolia 4.5 we provide the package info.magnolia.test.mock.jcr containing proper mock's for javax.jcr.Node, javax.jcr.Session etc. They're extending abstract types provided in [jackrabbit-commons|http://jackrabbit.apache.org/jackrabbit-jcr-commons.html]. The types of the Content API are now basically just wrapping these new mocks. If required you can always create a MockContent from a MockNode or a MockHierarchyManager from a MockSession.

...



With the help of info.magnolia.test.mock.jcr.SessionTestUtil MockNodes can be created from properties files

...


{code
:title
=CreateMockNodeFromPropertiesFile.java
}
MockSession session = SessionTestUtil.createSession("test", getClass().getResourceAsStream("sample.properties"));
{code}

as well as from String:

...


{code
:title
=CreateMockContentUsingAPI.java
}
MockSession session = SessionTestUtil.createSession("testWorkspace",
    "/foo/bar.@type=mgnl:content",
    "/foo/bar/sub1.@uuid=1",
    "/foo/bar/subpath.property=testName");
{code}

Of course there's also an proper API for it:

...


{code
:title
=CreateMockNodeUsingAPI.java
}
MockNode root = new MockNode();
root.addNode(MetaData.DEFAULT_META_NODE);
root.setProperty("stringProperty", "HelloWorld");
{code}