-
Notifications
You must be signed in to change notification settings - Fork 43
Write complex requirement with own schema
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
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:
<?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">
<user:db-name>USERS_ADMINISTRATION</user:db-name>
<user:ip>127.0.0.1</user:ip>
<user:port>1111</user:port>
</user:user-requirement>
</requirements>
</reddeer>
<?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>
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(){
}
}
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;
}
}
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;
}
}
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.
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.
<?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>
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());
}
}
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;
}
See also Requirements page and Test configuration page