:sources: ../../../../src/test/java/

== Testing
=== General
appNG also offers support for unit- and integration testing your appNG applications. Therefore, it uses the testing capabilities of the Spring framework. See the {spring}/spring-framework-reference/htmlsingle/#testing[Reference Documentation^] for details on testing with Spring.

To enable test support, just add the following dependency to your `pom.xml`:

[source,xml]
----
<dependency>
    <groupId>org.appng</groupId>
    <artifactId>appng-testsupport</artifactId>
    <version>${appNG.version}</version>
</dependency>
----

Next, use {appng}/org/appng/testsupport/TestBase.html[org.appng.testsupport.TestBase^] as a base class for your unit tests. You can test with or without JPA support enabled.


Without JPA support:
[source,java]
----
@org.springframework.test.context.ContextConfiguration(initializers = EmployeesTest.class)
public class EmployeesTest extends TestBase {

    public EmployeesTest() {
        super("myapp", "application-home");
    }

}
----

With JPA support:
[source,java]
----
@org.springframework.test.context.ContextConfiguration(
    locations = { TestBase.TESTCONTEXT_JPA }, initializers = EmployeesTest.class)
public class EmployeesTest extends TestBase {

    public EmployeesTest() {
        super("myapp", "application-home");
        setEntityPackage("com.myapp.domain");
        setRepositoryBase("com.myapp.repository");
    }

}
----

=== Testing a datasource
[source,java]
----
include::{sources}org/example/EmployeesTest.java[tag=datasource,indent=0]
----
<1> adds a parameter
<2> initialize the parameters, must be called after parameters have been added
<3> retrieve a `DataSourceCall` representing the datasource by its id
<4> get a `CallableDataSource`
<5> perform the `CallableDataSource`
<6> validate the response

In step 6, a {appng}/org/appng/testsupport/validation/WritingXmlValidator.html[org.appng.testsupport.validation.WritingXmlValidator^] is used to compare the contents of a *control file* with the XML that results from marshalling the given object (in this case a `org.appng.xml.platform.Datasource`). The control file must be located at `src/test/resources/xml`. It's name is derived from the name of the test class and the name of the test method. So in this example, it would be `EmployeesTest-testShowEmployees.xml`.

NOTE: For initially creating and later updating your control files, just set `WritingXmlValidator.writeXml = true` and the control files will be written to `src/test/resources/xml`.

=== Testing an action
[source,java]
----
include::{sources}org/example//EmployeesTest.java[tag=action,indent=0]
----
<1> retrieve an `ActionCall` representing the action by its event-id and id
<2> add required parameters to the action
<3> create a form bean
<4> retrieve a `CallableAction`
<5> perform the `CallableAction` receive a `FieldProcessor`
<6> use a `validate(...)`-method that takes a suffix as a parameter, validating the messages of the `fieldProcessor`
<7> use the same validate method to validte the contents of the action

NOTE: Although you pass the `formBean` as a whole to `ActionCall.getCallableAction(formBean)`, this `formBean` is being copied internally. This copy, which is passed to the `ActionProvider<T>`, will contain only those properties that are mapped and writable in the datasource used by the action.

=== Adding custom bean definitions for testing
You can add custom bean definitons for your tests. For example, if you want to run a SQL script to initialize your test database, you could provide a file `beans-test-xml` located at `src/test/resources`.

.beans-test.xml
[source,xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	xsi:schemaLocation="http://www.springframework.org/schema/jdbc
		http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd">

	<jdbc:initialize-database enabled="true" data-source="datasource"><!--1-->
		<jdbc:script location="classpath:/sql/init-db.sql" /><!--2-->
	</jdbc:initialize-database>
</beans>
----
<1> use `<jdbc:initialize-database>` and make a reference to the built in <<app-datasource, datasource>>
<2> set the classpath location for the DDL script

In your testcase, you just need to add `beans-test.xml` to the `@ContextConfiguration`-annotation.

[source,java]
----
@ContextConfiguration(locations = { TestBase.TESTCONTEXT_JPA, "classpath:/beans-test.xml" }
----

=== Test utilities
appNG comes along with some handy test utilities. 

==== Writing JSON Validator
The class {appng}/org/appng/testsupport/validation/WritingJsonValidator.html[org.appng.testsupport.validation.WritingJsonValidator^] is a utility to map Java objects to JSON and compare it against a reference file. It also provides the functionality to easily create the reference files at `src/test/resources/json` in your project.

NOTE: The folder for reference files must be created manually before creating reference files.

[source,java]
----

public class MyTest {

  static { // <1>
    WritingJsonValidator.writeJSON = false; // <2>
    WritingJsonValidator.sortPropertiesAlphabetically = true; // <3>
  }

  @Test
  public void testWithJSON(){
    ComplexObject co = new ObjectProviderUnderTest().getObject();
    WritingJsonValidator.validate(co,"/filename.json"); // <4>
  }

}  

---- 
<1> It is handy to configure general properties in a static block for all test methods of a test case.
<2> If the reference file does not exist or is outdated, set this property to `true` to create a new reference file.
<3> The order of object properties in a JSON file is not clearly defined. Set this property to `true` for an alphabetically ordered output.
<4> Call the `validate`-method of {appng}/org/appng/testsupport/validation/WritingJsonValidator.html[WritingJsonValidator^] with the object and the file name of the reference file to map the object to JSON and compare it against the JSON provided in the compare file.

NOTE: In Eclipse, a newly created reference file might not be available immediately after creation. The project must be refreshed first.