All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jars.nosqlunit-documentation.1.0.0.source-code.mongodb.xml Maven / Gradle / Ivy

The newest version!
<?xml version="1.0" encoding="UTF-8"?>
<chapter version="5.0" xml:id="mongodb" xmlns="http://docbook.org/ns/docbook"
	xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude"
	xmlns:svg="http://www.w3.org/2000/svg" xmlns:m="http://www.w3.org/1998/Math/MathML"
	xmlns:html="http://www.w3.org/1999/xhtml" xmlns:db="http://docbook.org/ns/docbook">
    
    <title>MongoDb Engine</title>
	
	<section>
		<title>MongoDb</title>

		<para>
			<application>MongoDb</application>
			is a
			<emphasis>NoSQL</emphasis>
			database that stores structured data as
			<emphasis>JSON-like</emphasis>
			documents with dynamic schemas.
		</para>

		<para>
			<emphasis role="bold">NoSQLUnit</emphasis>
			supports
			<emphasis>MongoDb</emphasis>
			by using next classes:
		</para>
		<para>
		<table border="1">
			<caption>Lifecycle Management Rules</caption>

			<tr>
				<td>In Memory</td>

				<td>
					<classname>com.lordofthejars.nosqlunit.mongodb.InMemoryMongoDb
					</classname>
				</td>
			</tr>

			<tr>
				<td>Managed</td>

				<td>
					<classname>com.lordofthejars.nosqlunit.mongodb.ManagedMongoDb
					</classname>
				</td>
			</tr>
		</table>
		</para>
		<para>
		<table border="1">
			<caption>Manager Rule</caption>

			<tr>
				<td>NoSQLUnit Management</td>

				<td>
					<classname>com.lordofthejars.nosqlunit.mongodb.MongoDbRule
					</classname>
				</td>
			</tr>
		</table>
		</para>
		<section>
			<title>Maven Setup</title>

			<para>
				To use
				<emphasis role="bold">NoSQLUnit</emphasis>
				with
				<application>MongoDb</application>
				you only need to add next
				dependency:
			</para>

			<example xml:id="conf.nosqlunit_dep">
				<title>NoSqlUnit Maven Repository</title>

				<programlisting language="xml"><![CDATA[<dependency>
	<groupId>com.lordofthejars</groupId>
	<artifactId>nosqlunit-mongodb</artifactId>
	<version>${version.nosqlunit}</version>
</dependency>]]></programlisting>
			</example>

			<para>
				Note that if you are plannig to use
				<emphasis role="bold">in-memory</emphasis>
				approach an extra dependency is
				required.
				<emphasis role="bold">In-memory</emphasis>
				mode is implemented
				using
				<emphasis>jmockmongo</emphasis>
				.
				<emphasis>JMockmongo</emphasis>
				is a new project that help with unit testing Java-based
				<application>MongoDb</application>
				Applications by starting an
				in-process
				<emphasis>Netty</emphasis>
				server that speaks the
				<emphasis>MongoDb</emphasis>
				protocol and maintains databases and
				collections in
				<acronym>JVM</acronym>
				memory. It is not a true embedded
				mode becuase it will starts a server, but in fact for now it is the best
				way to write
				<application>MongoDb</application>
				unit tests. As his
				author says it is an incomplete tool and will be improved every time a
				new feature is required.
			</para>

			<warning>
				<para>
					During development of this documentation, current
					<emphasis>jmockmongo</emphasis>
					version was 0.0.2-SNAPSHOT. Author is
					imporoving version often so before using one specific version, take a
					look at its
					<link xlink:href="https://github.com/thiloplanz/jmockmongo">website</link>
					.
				</para>
			</warning>

			<para>
				To install add next
				<link linkend="conf.jmockmongo_repo">
					repository
				</link>
				and
				<link linkend="conf.jmockmongo_dep">
					dependency
				</link>
				:
			</para>

			<example xml:id="conf.jmockmongo_repo">
				<title>jmockmongo Maven Repository</title>

				<programlisting language="xml"><![CDATA[<repositories>
	<repository>
		<id>thiloplanz-snapshot</id>
		<url>http://repository-thiloplanz.forge.cloudbees.com/snapshot/</url>
	</repository>
</repositories>]]></programlisting>
			</example>

			<example xml:id="conf.jmockmongo_dep">
				<title>jmockmongo Maven Dependency</title>

				<programlisting language="xml"><![CDATA[<dependency>
	<groupId>jmockmongo</groupId>
	<artifactId>jmockmongo</artifactId>
	<version>${mongomock.version}</version>
</dependency>]]></programlisting>
			</example>
		</section>

		<section>
			<title>Dataset Format</title>

			<para>
				Default dataset file format in
				<emphasis>MongoDb</emphasis>
				module
				is
				<emphasis>json</emphasis>
				.
			</para>

			<para>
				Datasets must have next
				<link linkend="ex.mongodb_dataset">
					format
				</link>
				:
			</para>

			<example xml:id="ex.mongodb_dataset">
				<title>Example of MongoDb Dataset</title>

				<programlisting language="json"><![CDATA[{
	"name_collection1": [
	{
		"attribute_1":"value1",
		"attribute_2":"value2"
	},
	{
		"attribute_3":2,
		"attribute_4":"value4"
	}
	],
	"name_collection2": [
		...
	],
	....
}]]></programlisting>
			</example>

			<para>Notice that if attributes value are integers, double quotes are
				not required.
			</para>
		</section>

		<section>
			<title>Getting Started</title>

			<section>
				<title>Lifecycle Management Strategy</title>

				<para>
					First step is defining which lifecycle management strategy is
					required for your tests. Depending on kind of test you are
					implementing (unit test, integration test, deployment test, ...)
					you
					will require an
					<emphasis role="bold">in-memory</emphasis>
					approach,
					<emphasis role="bold">managed</emphasis>
					approach or
					<emphasis role="bold">remote</emphasis>
					approach.
				</para>

				<para>
					To configure
					<emphasis role="bold">in-memory</emphasis>
					approach
					you should only instantiate next
					<link linkend="program.inmemory_conf">rule</link>
					:
				</para>

				<example xml:id="program.inmemory_conf">
					<title>In-memory MongoDb</title>

					<programlisting language="java"><![CDATA[@ClassRule
InMemoryMongoDb inMemoryMongoDb = new InMemoryMongoDb();]]></programlisting>
				</example>

				<para>
					To configure the
					<emphasis role="bold">managed</emphasis>
					way,
					you should use
					<classname>ManagedMongoDb</classname>
					rule and may
					require some <link linkend="program.managed_conf">configuration</link> parameters.
				</para>

				<example xml:id="program.managed_conf">
					<title>Managed MongoDb</title>

					<programlisting language="java"><![CDATA[import static com.lordofthejars.nosqlunit.mongodb.ManagedMongoDb.MongoServerRuleBuilder.newManagedMongoDbRule;

@ClassRule
public static ManagedMongoDb managedMongoDb = newManagedMongoDbRule().build();]]></programlisting>
				</example>

				<para>
					By default managed
					<emphasis>MongoDb</emphasis>
					rule uses next
					default values:
				</para>

				<itemizedlist>
					<listitem>
						<para>
							<emphasis>MongoDb</emphasis>
							installation directory is
							retrieved from
							<varname>MONGO_HOME</varname>
							system environment
							variable.
						</para>
					</listitem>

					<listitem>
						<para>
							Target path, that is the directory where
							<emphasis>MongoDb</emphasis>
							server is started, is
							<constant>target/mongo-temp</constant>
							.
						</para>
					</listitem>

					<listitem>
						<para>
							Database path is at
							<parameter>{target
								path}
							</parameter>
							<constant>/mongo-dbpath</constant>
							.
						</para>
					</listitem>

					<listitem>
						<para>
							Because after execution of tests all generated data is
							removed, in
							<parameter>{target
								path}
							</parameter>
							<constant>/logpath</constant>
							will remain log
							file generated by the server.
						</para>
					</listitem>

					<listitem>
						<para>
							In
							<emphasis>Windows</emphasis> systems
							executable should be found as
							<filename>bin/mongod.exe</filename>
							meanwhile in
							<emphasis>MAC
								OS
							</emphasis>
							and
							<emphasis>*nix</emphasis>
							should be found as
							<filename>bin/mongod</filename>
							.
						</para>
					</listitem>
				</itemizedlist>

				<para>
					<classname>ManagedMongoDb</classname>
					can be created from
					scratch, but for making life easier, a
					<emphasis>DSL</emphasis>
					is
					provided using
					<classname>MongoServerRuleBuilder</classname>
					class.
					For
					<link linkend="program.managed_specific_conf">example</link>
					:
				</para>

				<example xml:id="program.managed_specific_conf">
					<title>Specific Managed MongoDb Configuration</title>

					<programlisting language="java"><![CDATA[import static com.lordofthejars.nosqlunit.mongodb.ManagedMongoDb.MongoServerRuleBuilder.newManagedMongoDbRule;

@ClassRule
public static ManagedMongoDb managedMongoDb =
newManagedMongoDbRule().mongodPath("/opt/mongo").appendSingleCommandLineArguments("-vvv").build();]]></programlisting>
				</example>

				<para>
					In
					<link linkend="program.managed_specific_conf">example</link>
					we are overriding
					<varname>MONGO_HOME</varname>
					variable (in case has
					been set) and set mongo home at
					<filename>/opt/mongo</filename>
					.
					Moreover we are appending a single argument to
					<emphasis>MongoDb</emphasis>
					executable, in this case setting log
					level to number 3 (-vvv). Also you can append
					<emphasis>property=value</emphasis>
					arguments using
					<function>appendCommandLineArguments(String argumentName, String
						argumentValue)
					</function>
					method.
				</para>

				<warning>
					<para>when you are specifying command line arguments, remember to
						add slash (-) and double slash (--) where is necessary.
					</para>
				</warning>

				<para>
					To stop
					<emphasis>MongoDb</emphasis>
					instance,
					<emphasis role="bold">NoSQLUnit</emphasis>
					sends a
					<function>shutdown</function>
					command to server using
					<emphasis>Java Mongo AP</emphasis>
					I. When this
					command is sent, the server is stopped and because connection is lost,
					<emphasis>Java Mongo API</emphasis>
					logs automatically an exception
					(read
					<link
						xlink:href="https://groups.google.com/group/mongodb-user/browse_thread/thread/ac9a4c9ea13f3e81">here</link>
					information about the problem and how to "resolve" it). Do not
					confuse
					with a testing failure. You will see something like:
				</para>

				<screen><![CDATA[java.io.EOFException
	at org.bson.io.Bits.readFully(Bits.java:37)
	at org.bson.io.Bits.readFully(Bits.java:28)
	at com.mongodb.Response.<init>;(Response.java:39)
	at com.mongodb.DBPort.go(DBPort.java:128)
	at com.mongodb.DBPort.call(DBPort.java:79)
	at com.mongodb.DBTCPConnector.call(DBTCPConnector.java:218)
	at com.mongodb.DBApiLayer$MyCollection.__find(DBApiLayer.java:305)
	at com.mongodb.DB.command(DB.java:160)
	at com.mongodb.DB.command(DB.java:183)
	at com.mongodb.DB.command(DB.java:144)
	at
	com.lordofthejars.nosqlunit.mongodb.MongoDbLowLevelOps.shutdown(MongoDbLowLevelOps.java:44)
	at
	com.lordofthejars.nosqlunit.mongodb.ManagedMongoDb.after(ManagedMongoDb.java:157)
	at
	org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:48)
	at org.junit.rules.RunRules.evaluate(RunRules.java:18)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
	at
	org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:236)
	at
	org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:134)
	at
	org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:113)
	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:616)
	at
	org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
	at
	org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
	at
	org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
	at
	org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:103)
	at
	org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:74)]]></screen>

				<para>
					Configuring
					<emphasis role="bold">remote</emphasis>
					approach
					does not require any special rule because you (or System like
					<application>Maven</application>
					) is the responsible of starting and
					stopping the server. This mode is used in deployment tests where you
					are testing your application on real environment.
				</para>
			</section>

			<section>
				<title>Configuring MongoDb Connection</title>

				<para>
					Next step is configuring
					<emphasis>
						<emphasis role="bold">Mongodb</emphasis>
					</emphasis>
					rule in charge of
					maintaining
					<emphasis>MongoDb</emphasis>
					database into known state by
					inserting and deleting defined datasets. You must register
					<classname>MongoDbRule</classname>
					<emphasis>JUnit</emphasis>
					rule
					class, which requires a configuration parameter with information like
					host, port or database name.
				</para>

				<para>To make developer's life easier and code more readable, a
					fluent
					interface can be used to create these configuration objects. Two
					different kind of configuration builders exist.
				</para>

				<para>
					The first one is for configuring a connection to in-memory
					<emphasis>jmockmongo</emphasis>
					server. Default connection values
					are:
				</para>

				<table border="1">
					<caption>Default In-Memory Configuration Values</caption>

					<tr>
						<td>Host</td>

						<td>0.0.0.0</td>
					</tr>

					<tr>
						<td>Port</td>

						<td>2307</td>
					</tr>
				</table>

				<para>
					Notice that these values are the default ones of
					<emphasis>jmockmongo</emphasis>
					project, so if you are thinking to use
					<emphasis>jmockmongo</emphasis>
					, no modifications are required.
				</para>

				<example xml:id="program.in_memory_connection_parameters">
					<title>MongoDbRule with in-memory configuration</title>

					<programlisting language="java"><![CDATA[import static com.lordofthejars.nosqlunit.mongodb.InMemoryMongoDbConfigurationBuilder.inMemoryMongoDb;

@Rule
public MongoDbRule remoteMongoDbRule = new MongoDbRule(inMemoryMongoDb().databaseName("test").build());]]></programlisting>
				</example>

				<para>
					The second one is for configuring a connection to remote
					<emphasis>MongoDb</emphasis>
					server. Default values are:
				</para>

				<table border="1">
					<caption>Default Managed Configuration Values</caption>

					<tr>
						<td>Host</td>

						<td>localhost</td>
					</tr>

					<tr>
						<td>Port</td>

						<td>27017</td>
					</tr>

					<tr>
						<td>Authentication</td>

						<td>No authentication parameters.</td>
					</tr>
				</table>

				<example xml:id="program.managed_connection_parameters">
					<title>MongoDbRule with managed configuration</title>

					<programlisting language="java"><![CDATA[import static com.lordofthejars.nosqlunit.mongodb.MongoDbConfigurationBuilder.mongoDb;

@Rule
public MongoDbRule remoteMongoDbRule = new MongoDbRule(mongoDb().databaseName("test").build());]]></programlisting>
				</example>

				<example xml:id="program.remote_connection_parameters">
					<title>MongoDbRule with remote configuration</title>

					<programlisting language="java"><![CDATA[import static com.lordofthejars.nosqlunit.mongodb.MongoDbConfigurationBuilder.mongoDb;

@Rule
public MongoDbRule remoteMongoDbRule = new MongoDbRule(mongoDb().databaseName("test").host("my_remote_host").build());]]></programlisting>
				</example>
			</section>

			<section>
				<title>Complete Example</title>

				<para>
					Consider a library application, which apart from multiple
					operations, it allow us to add new books to system. Our
					<link linkend="example.book_model">model</link>
					is as simple as:
				</para>

				<example xml:id="example.book_model">
					<title>Book POJO</title>

					<programlisting language="java"><![CDATA[public class Book {

	private String title;

	private int numberOfPages;

	public Book(String title, int numberOfPages) {
		super();
		this.title = title;
		this.numberOfPages = numberOfPages;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public void setNumberOfPages(int numberOfPages) {
		this.numberOfPages = numberOfPages;
	}


	public String getTitle() {
		return title;
	}

	public int getNumberOfPages() {
		return numberOfPages;
	}
}]]></programlisting>
				</example>

				<para>
					Next business
					<link linkend="example.book_manager">class</link>
					is the responsible of managing access to
					<emphasis>MongoDb</emphasis>
					server:
				</para>

				<example xml:id="example.book_manager">
					<title>Book POJO</title>

					<programlisting language="java"><![CDATA[public class BookManager {

	private static final Logger LOGGER = LoggerFactory.getLogger(BookManager.class);

	private static final MongoDbBookConverter MONGO_DB_BOOK_CONVERTER = new	MongoDbBookConverter();
	private static final DbObjectBookConverter DB_OBJECT_BOOK_CONVERTER = new DbObjectBookConverter();

			
	private DBCollection booksCollection;

	public BookManager(DBCollection booksCollection) {
		this.booksCollection = booksCollection;
	}

	public void create(Book book) {
		DBObject dbObject = MONGO_DB_BOOK_CONVERTER.convert(book);
		booksCollection.insert(dbObject);
	}
}]]></programlisting>
				</example>

				<para>
					And now it is time for testing. In next
					<link linkend="example.test_insert_book">test</link>
					we are going to
					validate that a book is inserted correctly into database.
				</para>

				<example xml:id="example.test_insert_book">
					<title>Test with Managed Connection</title>

					<programlisting language="java"><![CDATA[package com.lordofthejars.nosqlunit.demo.mongodb;

public class WhenANewBookIsCreated {

	@ClassRule
	public static ManagedMongoDb managedMongoDb = newManagedMongoDbRule().mongodPath("/opt/mongo").build();

	@Rule
	public MongoDbRule remoteMongoDbRule = new MongoDbRule(mongoDb().databaseName("test").build());

	@Test
	@UsingDataSet(locations="initialData.json", loadStrategy=LoadStrategyEnum.CLEAN_INSERT)
	@ShouldMatchDataSet(location="expectedData.json")
	public void book_should_be_inserted_into_repository() {

		BookManager bookManager = new BookManager(MongoDbUtil.getCollection(Book.class.getSimpleName()));

		Book book = new Book("The Lord Of The Rings", 1299);
		bookManager.create(book);
	}

}]]></programlisting>
				</example>

				<para>
					In
					<link linkend="example.test_insert_book">previous</link>
					test
					we have defined that
					<emphasis>MongoDb</emphasis>
					will be managed by
					test by starting an instance of server located at
					<filename>/opt/mongo</filename>
					. Moreover we are setting an
					<link linkend="example.dataset_book">initial</link>
					dataset in file
					<filename>initialData.json</filename>
					located at classpath
					<filename>com/lordofthejars/nosqlunit/demo/mongodb/initialData.json
					</filename>
					and
					<link linkend="example.expected_dataset_book">expected</link>
					dataset called
					<filename>expectedData.json</filename>
					.
				</para>

				<example xml:id="example.dataset_book">
					<title>Initial Dataset</title>

					<programlisting language="json"><![CDATA[{
	"Book":
	[
		{"title":"The Hobbit","numberOfPages":293}
	]
}]]></programlisting>
				</example>

				<example xml:id="example.expected_dataset_book">
					<title>Expected Dataset</title>

					<programlisting language="json"><![CDATA[{
	"Book":
	[
		{"title":"The Hobbit","numberOfPages":293},
		{"title":"The Lord Of The Rings","numberOfPages":1299}
	]
}]]></programlisting>
				</example>

				<para>
					You can watch full example at
					<link
						xlink:href="https://github.com/lordofthejars/nosql-unit/tree/master/nosqlunit-demo">github</link>
					.
				</para>
			</section>
		</section>
	</section>

</chapter>




© 2015 - 2025 Weber Informatics LLC | Privacy Policy