Skip to content

Write complex requirement with own schema

rawagner edited this page Dec 10, 2015 · 15 revisions

Using your own XML schema is more complex than a property based configuration but has the advantage of:

  • Protects you from making typo errors
  • Allows you to refactor your code without a need for changes in configuration files, and
  • Enables you to mark some properties as required so that XML schema validation will prevent you from forgetting some parameters

It is intended to use this approach mainly if you provide your requirements for other teams or components.

In this page we will describe each step of using XML schema (creating XML schema, XML configuration file, XML configuration and a special configuration object that will be injected into requirement)

Don't forget to specify the following property on the command line, when you run the tests, in order to point to configuration file:

-Drd.config=/home/path/to/xml-file/or/directory-with-xml-files

Example

Let's say you have many configuration options or you want to use the same user requirements in several configuration files. You can create a simple XSD schema and read it using JAXB annotations all within a Red Deer configuration file:

Configuration File

<?xml version="1.0" encoding="UTF-8"?>
<reddeer
	xmlns="http://www.jboss.org/NS/Req" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:user="http://www.jboss.org/NS/user-schema"
	xsi:schemaLocation="http://www.jboss.org/NS/Req RedDeerRequirements.xsd http://www.jboss.org/NS/user-schema user-schema.xsd">

	<requirements>
		<user:user-requirement name="user-requirement">
			&lt;user:db-name>USERS_ADMINISTRATION</user:db-name>
			&lt;user:ip>127.0.0.1</user:ip>
			&lt;user:port>1111</user:port>
		</user:user-requirement>
	</requirements>
</reddeer>

XSD schema (user-schema.xsd)

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        elementFormDefault="qualified"
        targetNamespace="http://www.jboss.org/NS/user-schema"
        xmlns:user="http://www.jboss.org/NS/user-schema"
        xmlns:rd="http://www.jboss.org/NS/Req">

        <!-- Import basic RedDeer requirements -->
        <xs:import namespace="http://www.jboss.org/NS/Req" schemaLocation="http://www.jboss.org/schema/reddeer/v1/RedDeerSchema.xsd" />

        <!-- Specify user-requirement -->
        <xs:element name="user-requirement" type="user:userRequirementType" substitutionGroup="rd:abstractRequirement">
                <xs:annotation>
                        <xs:documentation>Specifies all data needed to create a user in the database</xs:documentation>
                </xs:annotation>
        </xs:element>

        <!-- type for user-requirement -->
        <xs:complexType name="userRequirementType">
                <xs:complexContent>
                        <xs:extension base="rd:abstractRequirementType">
                                <xs:sequence>
                                        <xs:element name="db-name" type="xs:string" minOccurs="1" maxOccurs="1"/>
                                        <xs:element name="ip" type="xs:string" minOccurs="1" maxOccurs="1"/>
                                        <xs:element name="port" type="xs:string" minOccurs="1" maxOccurs="1"/>
                                </xs:sequence>
                        </xs:extension>
                </xs:complexContent>
        </xs:complexType>
</xs:schema>

Requirement Usage

This is how you declare the requirement that user with name ''admin'' has to be present in the database:

@RunWith(RedDeerSuite.class)
@User(name="admin")
public class UserTest {
        @Test
        public void test(){

        }
}

Requirement Configuration

To read the configuration from the Red Deer configuration file using your own schema you need to create a configuration object with JAXB annotations:

@XmlRootElement(name="user-requirement", namespace="http://www.jboss.org/NS/user-schema")
public class UserConfiguration {

	private String dbName;

	private String ip;

	private String port;

	public String getIp() {
		return ip;
	}

	@XmlElement(namespace="http://www.jboss.org/NS/user-schema")
	public void setIp(String ip) {
		this.ip = ip;
	}

	public String getPort() {
		return port;
	}

	@XmlElement(namespace="http://www.jboss.org/NS/user-schema")
	public void setPort(String port) {
		this.port = port;
	}

	public String getDbName() {
		return dbName;
	}

	@XmlElement(name="db-name", namespace="http://www.jboss.org/NS/user-schema")
	public void setDbName(String dbName) {
		this.dbName = dbName;
	}
}

Requirement

Since it is possible to use requirements without any configuration or with a property based configuration, you need to let Red Deer know that you'd like to use a custom configuration by implementing CustomConfiguration. You'll also need to indicate the class of JAXB annotated object (called Userconfiguration):

public class UserRequirement implements Requirement<User>, CustomConfiguration<UserConfiguration> {

	@Retention(RetentionPolicy.RUNTIME)
	@Target(ElementType.TYPE)
	public @interface User {
		String name();
	}

	private User user;

	private UserConfiguration userConfiguration;

	public boolean canFulfill() {
		// return true if you can connect to the database
		return true;
	}

	public void fulfill() {
		// create an admin user in the database if it does not exist yet
	}

	public void setDeclaration(User user) {
		this.user = user;
	}

	public Class<UserConfiguration> getConfigurationClass() {
		return UserConfiguration.class;
	}

	public void setConfiguration(UserConfiguration config) {
		this.userConfiguration = config;
	}
}

example source

Accessing XML configuration from within test class

It is also possible to inject the whole Requirement instance into the test class so that you are able to access the configuration defined in the XML file.

Example

You need to access user's password (defined in the XML configuration file) in your test. You can inject the whole UserRequirement instance into the test's property and access all data that the requirement exposes.

Configuration file

    <?xml version="1.0" encoding="UTF-8"?>
    <reddeer
        xmlns="http://www.jboss.org/NS/Req"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.jboss.org/NS/Req http://www.jboss.org/schema/reddeer/v1/RedDeerSchema.xsd">

        <requirements>
                <requirement class="org.jboss.reddeer.wiki.user.db.password.UserRequirement" name="userRequirement">
			<property key="name" value="USERS_ADMINISTRATION" />
			<property key="ip" value="127.0.0.1" />
			<property key="password" value="abc123" />
		</requirement>
        </requirements>
    </reddeer>

Requirement Usage

This is how you inject the UserRequirement instance into the test and access the password:

@RunWith(RedDeerSuite.class)
@User(name="admin")
public class UserTest {
	
	@InjectRequirement
	private UserRequirement userRequirement;
	
	@Test
	public void test(){
		System.out.println(userRequirement.getPassword());
	}
}

Requirement

The UserRequirement needs to provide methods for accessing data (in this case getPassword()):

public class UserRequirement implements Requirement<User>, PropertyConfiguration{

	@Retention(RetentionPolicy.RUNTIME)
	@Target(ElementType.TYPE)
	public @interface User {
		String name();
	}
	
	private User user;
	
	private String name;
	
	private String ip;
	
	private String password;
	
	public boolean canFulfill() {
		// return true if you can connect to the database
		return true;
	}

	public void fulfill() {
		user.name();
		// create an admin user in the database if it does not exist yet
	}
	
	@Override
	public void setDeclaration(User user) {
		this.user = user;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public void setIp(String ip) {
		this.ip = ip;
	}
	
	public void setPassword(String password) {
		this.password = password;
	}
	
	public String getPassword() {
		return password;
	}

example source

See also Requirements page and Test configuration page

Clone this wiki locally