/**
* Copyright (c) 2012 BMW Car IT and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.jnario.feature.documentation;
import org.eclipse.xtend2.lib.StringConcatenation;
import org.jnario.feature.documentation.IntroducingJnarioFeaturesSpec;
import org.jnario.jnario.test.util.FeatureExecutor;
import org.jnario.runner.ExampleGroupRunner;
import org.jnario.runner.Named;
import org.jnario.runner.Order;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* First of all you need a running installation of Jnario. If you haven't installed
* Jnario yet, follow the [install guide](../../jnario/documentation/InstallingJnarioSpec.html).
* To get started create a new specification using the spec wizard
* (**File** -> **New** -> **Other** -> **Jnario** -> **Feature**).
*
* <p align="center"><img src="/img/tutorial/feature_wizard.png" alt="New Feature Wizard"/></p>
*
* <span class="label label-info">Tip</span> If the editor shows a validation error,
* because of the missing jnario libraries, add them
* to the classpath using the quickfix (CMD/Ctrl + 1).
*
* A feature file consists of a feature and the scenarios that are the acceptance criteria for the feature.
* For the calculator the the feature description in form of a story and one scenario for adding
* numbers looks as follows:
*
* <pre class="prettyprint lang-feature">
* Feature: Calculator
*
* As a math dummy
* I want a calculator that helps me with basic math operations
* In order to check my capabilities
*
* Scenario: Adding two numbers
*
* Given a calculator
* When I enter two numbers and press add
* Then it should show the sum
* </pre>
*
* A feature consists of the name of the feature, it's narrative and a number of scenarios. The narrative can be arbitrary
* text. You should use it to describe the rationale of the feature.
* Those scenarios
* are examples for the behavior expected from the feature. Possible scenarios for the calculator
* are, for example, addition or subtraction.
*
* Each scenario is defined by the steps that describe the expected behavior. **Given** steps give
* all the necessary information about the context of the scenario. **When** describes the action
* and **Then** describes the expected outcome that we want to verify. You can use the keyword **And** to
* split a step into different sub steps.
*
* When you save the file an xtend-gen folder will be created and the corresponding generated java files will
* be created. Those files can be executed as JUnit-Tests. It is possible to run those tests directly from
* the feature file. Right click in the feature file after saving it and select **Run As** -> **JUnit Test**.
* You will see the result of the run and it will be green. Since the steps from scenario are not implemented
* yet all the steps will be marked as _PENDING_ as a reminder that there is still work to do.
*/
@Named("How to write a Feature?")
@RunWith(ExampleGroupRunner.class)
@SuppressWarnings("all")
public class IntroducingJnarioFeaturesHowToWriteAFeatureSpec extends IntroducingJnarioFeaturesSpec {
/**
* @filter('''|.isSuccessful)
* @lang(feature)
*
* To turn our scenario into an executable specification you have to add the necessary code to each
* of our steps. For each step the implementation is done directly after the description
* of the step. The language used to define the logic is [Xtend](http://www.eclipse.org/xtend/documentation/index.html#fields).
* Create a Java class with the name Calculator in the same project as your feature file.
* Add the necessary import to the feature file or include it by auto completion while typing (CTRL + SPACE).
*
* <span class="label label-info">Info</span> Specifying the package and declaring and importing other packages
* works similar to Xtend (static imports work as well).</span>
*
* First we will declare a field `Calculator calculator` which we initialize in our **Given** step (we could
* also directly initialize the field `Calculator calculator = new Calculator`). We will also create a
* integer field named `result` to store the result of our calculation. Variables that are defined after the
* scenario description and before the first step are fields inside of the scenario. This means every step
* can use fields that were declared after the scenario description. Variables that are declared with var or val
* after a step description can only be used locally inside the step.
*
*
* In the **When** step we call `add` on the calculator that also needs the two numbers that should be added.
* In a Jnario feature it is possible to define parameters inside of a step description. Parameters can be
* defined in steps using quotes: `"I am a parameter"`. Within your step implementation,
* you can access these parameters by an implicitly created variable `args`.
*
* The parameters from the when step are passed to the add method. Jnario provides some
* [extension methods](http://www.eclipse.org/xtend/documentation/index.html#extensionMethods) that
* simplify converting strings to other primitives. Here we use the `toInt` extension to convert the
* string parameter into an integer.
* Finally, the return value of the add method is assigned to the `result` field.
*
* Now we need to define a method `add` in our calculator to remove the compile errors.
* In the **Then** step we will assert the behavior of our calculator. For writing readable short assertions
* different additional assertions come with Jnario. All of the possibilities are
* described [here](/org/jnario/spec/tests/integration/AssertionSpec.html).
* Here we use for describing the expected outcome of an expression `=>`.
*
* @filter('''|.isSuccessful)
* @lang(feature)
*/
@Test
@Named("Implementing Steps")
@Order(1)
public void _implementingSteps() throws Exception {
StringConcatenation _builder = new StringConcatenation();
_builder.append("package demo");
_builder.newLine();
_builder.newLine();
_builder.append("import org.jnario.feature.documentation.Calculator");
_builder.newLine();
_builder.newLine();
_builder.append("Feature: Calculator");
_builder.newLine();
_builder.newLine();
_builder.append("Scenario: Adding two numbers");
_builder.newLine();
_builder.append(" ");
_builder.append("Calculator calculator");
_builder.newLine();
_builder.append(" ");
_builder.append("int result");
_builder.newLine();
_builder.append(" ");
_builder.append("Given a calculator");
_builder.newLine();
_builder.append(" ");
_builder.append("calculator = new Calculator");
_builder.newLine();
_builder.append(" ");
_builder.append("When I add two numbers \"20\" and \"70\"");
_builder.newLine();
_builder.append(" ");
_builder.append("result = calculator.add(args.first.toInt, args.second.toInt)");
_builder.newLine();
_builder.append(" ");
_builder.append("Then it prints \"90\"");
_builder.newLine();
_builder.append(" ");
_builder.append("result => args.first.toInt");
_builder.newLine();
FeatureExecutor.isSuccessful(_builder);
}
/**
* **Given** steps that are used in all scenarios of the same feature can be defined in a `Background`.
* For example, if we add a second scenario to describe the division of two values, we can move the
* **Given** step together with it's used fields to a **Background**.
* All steps defined as background steps will be executed before each steps of a scenario.
*
* @filter('''|.isSuccessful)
* @lang(feature)
*/
@Test
@Named("Background")
@Order(2)
public void _background() throws Exception {
StringConcatenation _builder = new StringConcatenation();
_builder.append("package demo");
_builder.newLine();
_builder.newLine();
_builder.append("import org.jnario.feature.documentation.Calculator");
_builder.newLine();
_builder.newLine();
_builder.append("Feature: Calculator");
_builder.newLine();
_builder.newLine();
_builder.append("Background:");
_builder.newLine();
_builder.append(" ");
_builder.append("Calculator calculator");
_builder.newLine();
_builder.append(" ");
_builder.append("int result");
_builder.newLine();
_builder.append(" ");
_builder.append("Given a calculator");
_builder.newLine();
_builder.append(" \t");
_builder.append("calculator = new Calculator");
_builder.newLine();
_builder.newLine();
_builder.append("Scenario: Adding two numbers");
_builder.newLine();
_builder.append(" ");
_builder.append("When I add two numbers \"20\" and \"70\"");
_builder.newLine();
_builder.append(" ");
_builder.append("result = calculator.add(args.first.toInt, args.second.toInt)");
_builder.newLine();
_builder.append(" ");
_builder.append("Then it prints \"90\"");
_builder.newLine();
_builder.append(" ");
_builder.append("result => args.first.toInt");
_builder.newLine();
_builder.append(" ");
_builder.newLine();
_builder.append("Scenario: Dividing two numbers");
_builder.newLine();
_builder.append(" ");
_builder.append("When I divide \"70\" by \"10\"");
_builder.newLine();
_builder.append(" \t ");
_builder.append("result = calculator.divide(args.first.toInt, args.second.toInt)");
_builder.newLine();
_builder.append(" ");
_builder.append("Then it prints \"7\"");
_builder.newLine();
FeatureExecutor.isSuccessful(_builder);
}
/**
* Once a step is defined including the execution code it can be referenced from
* other scenarios. The textual description of the step serves as identifier.
* When you reuse the step in a different scenario and provide no implementation
* the existing implementation from the referenced step will be used for this step.
*
* Referenced steps are highlighted in grey so you see when you are actually using
* a referenced step. You can also jump directly to the original step declaration
* to have a look at the implementation.
*
* @filter('''|.isSuccessful)
* @lang(feature)
*/
@Test
@Named("Step references")
@Order(3)
public void _stepReferences() throws Exception {
StringConcatenation _builder = new StringConcatenation();
_builder.append("package demo");
_builder.newLine();
_builder.append("import org.jnario.feature.documentation.Calculator");
_builder.newLine();
_builder.newLine();
_builder.append("Feature: Calculator");
_builder.newLine();
_builder.newLine();
_builder.append("Background:");
_builder.newLine();
_builder.append(" ");
_builder.append("Calculator calculator");
_builder.newLine();
_builder.append(" ");
_builder.append("int result");
_builder.newLine();
_builder.append(" ");
_builder.append("Given a calculator");
_builder.newLine();
_builder.append(" ");
_builder.append("calculator = new Calculator");
_builder.newLine();
_builder.newLine();
_builder.append("Scenario: Adding two numbers");
_builder.newLine();
_builder.append(" ");
_builder.append("When adding two numbers \"5\" and \"6\". ");
_builder.newLine();
_builder.append(" ");
_builder.append("result = calculator.add(args.first.toInt, args.second.toInt)");
_builder.newLine();
_builder.append(" ");
_builder.append("Then it prints \"11\"");
_builder.newLine();
_builder.append(" ");
_builder.append("result => args.first.toInt");
_builder.newLine();
_builder.append(" ");
_builder.newLine();
_builder.append("Scenario: Dividing two numbers");
_builder.newLine();
_builder.append(" ");
_builder.append("When entering two numbers \"10\" and \"5\" and pressing enter. ");
_builder.newLine();
_builder.append(" ");
_builder.append("result = calculator.divide(args.first.toInt, args.second.toInt)");
_builder.newLine();
_builder.append(" ");
_builder.append("Then it prints \"2\"");
_builder.newLine();
FeatureExecutor.isSuccessful(_builder);
}
}