EcFeed was initially created to support model based testing of Java code. After a while the connections with Java were tightened, but to show the maximum of the ecFeed's functionality, we will assume that the model represents a Java project. Thus, we assume basic understanding of the Java code organisation (packages, classes) and the syntax (naming rules, types).
Let's start from creating a new model. Login and go to the "My projects" page. Click the "New project" button. You can rename the project as you want. Then click on it to open the model editor.
The editor window contains of two parts. On the left pane you can see the model tree. We will refer to it as model page . The right pane, called details page, shows the details of the currently highlighted node on the model pane.
Initially, the model contains only a single root node. It has the same name as you called the model on the "My projects" page, but in general those two names are independent. So changing this name will not affect name of the model as well as changing the model name will not affect this node. Lets' rename the model to "Tutorial", just to confirm that. You can do it using the text box on the top of the model details page.
To show how to use ecFeed we will create a model of a bank application that processes customer data and decides whether to grant them a loan. We will start by adding a test class to the model. This is done in the context menu of the root node in the model page or by clicking the "Add class" buton in the Classes viewer in the model details page. Add a test class and change it's name to "LoanDecisionTest".
We have to stick to naming rules for Java classes (alphanumeric string, no spaces, starts from letter, no reserved keywords etc.). By convention, Java classes are named using nouns with each letter capitalized. Sticking to this convention will not hurt and will help us avoiding some potential problems in the future. Leave the package name unchanged (com.example.test).
Now, let's add a test method to our class. Our first test method will be used to generate example data of customers that may want to get a loan in our bank. So let's call the test method "generateCustomerData".
The first parameter that we want to have for our user is it's name. Add a parameter to the method (you probably figured out how to do it by now). You can change the parameter's name and its type directly in the parameters viewer, in the method details page, or in the parameter details page. Change the name to "familyName" and the type to String.
We will add some choices now. A choice represents a value that can be taken by the parameter. A good test design should consider a set of typical values taken by the parameter, but also all corner cases. The parameter name is not constrained by any Java rules, it just needs to have a reasonable length. The choice value on the other hand must be a valid for the parameters type. Let's add the following choices for the familyName parameter (values are provided in the parentheses):
Now we will add a parameter representing the first name. Let's name it firstName and change its type to String, as in the case of familyName.
In the case of family names, at least in English, the form doesn't determine the owner's gender. That is not the case of given names, so it may have sense to distinguish male and female names. Let's then add two choices to the firstName parameter: male and female. Do not bother to define values for these choices as they will never be used. Instead, add three choices to both male and female choices:
Choices that have other choices as children will be referred as abstract choices. Choices on the bottom of the hierarchy will be called leaf choices.
So far we defined two String parameters for which all choices had precisely defined values. In many cases we are not interested in concrete value, but rather in range of values or a certain pattern for String parameter. EcFeed supports this case by so called randomized choices. Values of randomized choices are not defined until the test is executed or exported (see section Data export).
Add a new parameter to our method, name it age and change its name to int. Add a choice to this parameter and name it minor. Now if you look at the choices viewer you will see a column named "Randomized". There is also a "Randomized" checkbox in the choice details page. Set it to "Yes" for the minor choice. The value of the choice should now change to 0:0. In the choice details page, the word "Value" should be replaced by "Range". Indeed, we can now define a range of our choice. The numbers separated by a colon represent the lower and upper bounds of the range inclusively, so let's define it as 10:17 (We can assume age of 10 to be minimal required by bank for having an account). Let's add some more choices for age:
Similarily, we can define a randomized choice for a String parameter, but instead the range, we will define a regular expression representing the choice. When needed, the actual value will be randomly selected in a way that it will match the regex.
Lets add a String parameter called documentSerialNumber. We will add three choices for that parameter: drivers license, personal ID and passport. Let's assume that the driver's license number consists of single capital letter and seven digits. ID number will contain three letters followed by six digits, whereas passport id will be two letters and nine digits. So choices for our parameters will have the following values:
So far we used parameter types that correspond to Java built in types (int, String, boolean, etc.). EcFeed allows users to define their own types. These types represent Java enums. The use of the user types looks similar to enums, but there are some significant differences, for example, when the user types are used for output parameters (see Expected parameters). Let's add a parameter that will define a type of a document of which the serial number was provided. We will call it documentType. Now, in the Type column in the parameters viewer on the method details page, instead selecting a type from a combo box, we will enter our own type that is com.example.test.DocumentType. We can add choices for that parameter as for any other parameter, with couple of exceptions:
Let's also create an another parameter called gender with type com.example.test.Gender with two choices:
With drag&drop you can place them higher between customer's name and age.
Constraints are used to define which test cases will be included in the test output. Using constraints we can filter-out unwanted test cases.
A constraint is a logical expression in form PREMISE=>CONSEQUENCE, where a both PREMISE and CONSEQUENCE are logical statements in one of following forms:
Premise of a constraint works as a preliminary filter of test cases. If a premise evaluates to false, the constraint evaluates to true without the evaluation of the consequence.
If a premise evaluates to true, then the consequence is evaluated. In this case the result of the consequence evaluation is taken as a result of the constraint.
Constraints are evaluated one after another. If any constraint evaluates to false, the test case is removed from the test generation results.
A constraint in a model is a child of a method node, so it can be added from the method node context menu in the model page or in the method details page by clicking on the "Add constraint" button in the constraints viewer.
Let's add a constraint in our method and name it gender. A newly added constraint has a neutral form true=>true so it will always be satisfied. Go to the constraint's details page. We want to define a relationship between customer's gender and its given name. The constraint should ensure that whenever male choice is selected for Gender parameter, also one of choices that are leafs of male choice is selected for firstName parameter. Similarily for the female value of Gender. In other words, we want to filter out cases where the gender of Gender and firstName do not match. Use constraint editor to define following constraint:
Click on the constraint's premise statement (the upper true). Now at the bottom of the details page you can edit the statement. Select OR from the combo box. Now, click two times "_Add statement" button next to constraint editor. You added two statements under the OR node, so now if one of them will be evaluated to true, the entire statement will evaluate to true as well (you know how boolean logic works, don't you). Change both statements to AND, and add two sub-statements for each. Now select one of the newly added statements (it should be a static "true" value). In the combo box below the editor, select gender. You should see two other boxes appearing. The middle one defines the relation and the right one defines the compared element. We want the premise to have form gender=male[choice] (the word choice will distinguish the type of the right hand side element in case we defined a parameter or a label named male). Edit the other statements to get the constraint that we defined above. The consequence statement should be statically set to false.
Now we want to create a constraint for defining a relationship between documentType and documentSerialNumber parameters. Instead using complex logical expression like above, we can do it by three separate constraints. Add three constraints to the method and call all of them document type. Edit them, so they have the following forms:
Finally! We can now generate some data from the model. Right click on the method node in the model page and choose "Generate test suite" from the context menu. You can also scroll down the method details page to the test cases viewer and click "Generate test suite button". You will be prompted with a generator dialog to configure the generation process.
In the dialog, you can select which constraints and which choices will be considered for the generation. By default, all are selected what is fine for most of the cases, including ours. Below the choices selection viewer you can enter a name for the test suite that will be generated. Let's change it to "pairwise". Then, let's configure the generator that will be employed for the process. Make sure that it is set to "N-Wise". Each generator can be customized with different parameters. For N-Wise this is N that defines the size of tuples we want to cover (2 for pairwise, 3 for three way and so forth). The coverage parameter defines the percentage of tupes we want to cover. The default values (2 and 100) are fine so let's proceed with the generation by clicking the "OK" button.
After a short while we should be ready. Go to the bottom of method details page and check that a "pairwise" test suite appeared in the test cases viewer. It should contain around 30 test cases (the generation alogrithm is not deterministic, so each time the result can be different).
You can click the "Calculate coverage" button next to the test cases viewer to verify how many pairs we covered. You will see that over 94% of pairs are covered in the test suite. Of course we didn't cover all, because we filtered out some of them by constraints (for example the pair containing "female" as gender and any of male names couldn't be covered).
Generating test data is cool, but what can we do with it? One of the ways to use the generated data is to export them to a custom text format. To do it, first select the "pairwise" test suite in the test cases viewer and then click the "Export selcted" button. You will see a dialog where you can define a template that will be used for the export. You can select a predefined template (CSV, Gherkin or XML) and customize it. For more details about customization please refer to Export templates. Below the template editor you can see preview how generated data will look like. When you click "OK" you will be prompted with a download dialog where you can decide where to download the exported file. Note that the exported data contains actual values of randomized choices for age and documentSerialNumber parameters.
If you just want to export data without storing the test suite in the model, you can do it by clicking the "Export online..." button on top of the method details page. Then, generated data instead of being added to the model will be directly exported. The dialog that will appear, will allow to customize the generation process and select one of the predefined templates. If you want to customize the template, click "Advanced..." button.