Newer
Older
[](https://gitlab.cs.ui.ac.id/pmpl/examples/sitodo-pmpl/-/commits/main)
[](https://gitlab.cs.ui.ac.id/pmpl/examples/sitodo-pmpl/-/commits/main)
A basic todo app project for teaching basic Web programming, Git workflows, and
CI/CD. Heavily inspired by the running example in "Test-Driven Development with
Python" book by Harry Percival.
> Note: The project has been customised from [the upstream](https://github.com/addianto/sitodo)
> in order to be used in PMPL (SQA) course at the Faculty of Computer Science Universitas Indonesia.
## Table of Contents
1. [Getting Started](#getting-started)
1. [Setting Up Development Environment](#setting-up-development-environment)
2. [Build & Run](#build--run)
3. [Running Example](#running-example)
2. [Tutorial: Writing Behavior-Driven Development (BDD) Test Suite](#tutorial-writing-behavior-driven-development-bdd-test-suite)
3. [License](#license)
## Getting Started
### Setting Up Development Environment
The following tools need to be installed in order to build and run the project:
- [Java 17 JDK (Java Development Kit)](https://adoptium.net)
- PostgreSQL 14
- You can install PostgreSQL system-wide or use container (Docker/Podman)
- A [`docker-compose.yml`](./docker-compose.yml) exists to quickly start a PostgreSQL and pgAdmin containers
- [Apache Maven 3.8.5](https://maven.apache.org/download.cgi)
- [Mozilla Firefox](https://www.mozilla.org/en-US/firefox/)
- Required by the functional (Selenium) test suite and BDD test suite
Ensure `java`, `javac`, and `mvn` commands can be invoked from inside the shell:
```shell
$ java --version
openjdk 17.0.3 2022-04-19
OpenJDK Runtime Environment Temurin-17.0.3+7 (build 17.0.3+7)
OpenJDK 64-Bit Server VM Temurin-17.0.3+7 (build 17.0.3+7, mixed mode, sharing)
$ javac --version
javac 17.0.3
$ mvn --version
Apache Maven 3.8.2 (ea98e05a04480131370aa0c110b8c54cf726c06f)
```
We recommend [IntelliJ IDEA](https://www.jetbrains.com/idea/) Community Edition
as the IDE for developing the project. Other IDE or text editors, such as Eclipse
and Visual Studio Code, might work. However, we may not be able to help troubleshoot
any IDE-related issues. In addition, we include IntelliJ-specific **run configurations**
in the codebase that will add shortcuts for running the test suites and coverage
reporting from within IntelliJ.
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
To run the whole test suite, execute:
```shell
mvn test
```
> To run a select test suite, e.g. unit or functional test, add `-Dgroups`
> parameter. For example, to run only the unit test suite, execute
> `mvn test -Dgroups=unit`. Similarly, to run only the functional test suite,
> execute `mvn test -Dgroups=e2e`.
To build an executable Spring Boot application, execute:
```shell
mvn package -DskipTests
```
> The `-DskipTests` option lets `package` task to build the app into executable
> JAR file without running all test suites. If the option was omitted, then
> all test suites will run, thus increasing the duration of the building process,
> especially the functional test suite that runs much longer than the unit test
> suite.
The JAR file will be generated at [`./target`](./target) directory. To run it,
execute:
```shell
java -jar sitodo.jar
```
You can customise the configuration by providing an `application.properties`
file in the same directory as the executable JAR file. See the built-in
configuration in the [source code](./src/main/resources/application.properties).
You can also set the configuration during runtime using environment variables.
Following Spring Boot convention, properties are named in all uppercase and dot separators are replaced with underscores.
For instance, `spring.datasource.url` becomes `SPRING_DATASOURCE_URL` when configured using an environment variable.
See the example in the [GitLab CI/CD configuration](./.gitlab-ci.yml), specifically in the job for running tests.
See the running example based on the [upstream's `main` branch](https://gitlab.cs.ui.ac.id/pmpl/examples/sitodo-pmpl/-/tree/main) at [Fly.io](https://sitodo-pmpl.fly.dev).
## Tutorial: Writing Behavior-Driven Development (BDD) Test Suite
Previously, the lecture session in the class has explained the motivation and the basics of BDD.
This tutorial will cover the practical aspects by outlining the basic steps of writing BDD test suite.
We will see the process of writing the test scenarios and the "glue" code,
followed by running the test suite and generating the test report.
Finally, we will do an exercise to write new test scenarios and the corresponding "glue" code,
while maintaining the correctness and the code coverage.
### Executable Test Scenario
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
The executable test scenario in BDD usually follows a structured outline.
In this example, we follow the `Given-When-Then` format.
`Given` is to set up the pre-conditions, `When` is to perform the action, and `Then` is to verify the result.
For example, look at the following test scenario for ["Add new todo" feature](./src/test/resources/features/todo/add_new_todo.feature):
```gherkin
Feature: Add items into the todo list
Scenario: Add single item into the list
Given Alice is looking at the TODO list
When she adds "Touch grass" to the list
Then she sees "Touch grass" as an item in the TODO list
Scenario: Add multiple items into the list
Given Alice is looking at the TODO list
When she adds "Buy bread" to the list
And she adds "Buy candy" to the list
Then she sees "Buy bread" as an item in the TODO list
And she sees "Buy candy" as an item in the TODO list
```
One of the advantages of following this format is that the test scenario can be easily written by non-technical roles.
They can focus on writing the test scenario without worrying about the implementation details.
Eventually, there needs some way to "glue" the test scenario into the actual test code.
That is, the test scenario that is written in Gherkin format drives the test procedures in the test code.
To achieve that, we will write the "glue" code and also apply two patterns relevant to our need:
Screenplay & Page Object Model (POM).
> Note: There also exists the equivalent keywords in other languages such as Bahasa Indonesia.
> For example, `Given`, `When`, and `Then` are equals to `Jika`, `Ketika`, and `Maka`, respectively.
> You can check the available Bahasa Indonesia keywords as Java classes in `io.cucumber.java.id` package.
> See also the [Localization package on Cucumber website](https://cucumber.io/docs/gherkin/languages/).
> It might be useful if you want to write the test scenarios in a natural language other than English.
We use the Page Object Model pattern to represent the significant elements of the user interface (UI)
(i.e. the HTML elements) in a more readable and reusable way for the test code.
While we can use the selector method provided by Selenium or Selenide to obtain the reference to a UI element,
it is more preferred to follow the Page Object Model since the BDD test scenarios has to be writable and readable both
by technical (e.g. developer, QA) and non-technical (e.g. user, business analyst) roles.
> TODO: Page Object Model
> TODO: Screenplay
For example, see the code in `helpers` and `stepdefinitions`.
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
Before we run the BDD test suite, let us see how it is configured first at
[`CucumberTestSuite.java`](./src/test/java/com/example/sitodo/bdd/CucumberTestSuite.java):
```java
package com.example.sitodo.bdd;
import io.cucumber.junit.CucumberOptions;
import net.serenitybdd.cucumber.CucumberWithSerenity;
import org.junit.runner.RunWith;
/**
* The test runner class that runs the executable scenarios,
* i.e. the feature files written in Gherkin format.
*/
@RunWith(CucumberWithSerenity.class) // Runs the test suite using the test runner provided by Serenity
@CucumberOptions(
plugin = {"pretty"},
features = "src/test/resources/features"
)
public class CucumberTestSuite { }
```
The Java class represents the BDD test suite.
It specifies the test runner, i.e. `CucumberWithSerenity` Java class,
and the options for the test runner such as the location of the test scenarios.
The options for the test runner provided by Serenity can also be provided via a configuration file named [`serenity.conf`](./src/test/resources/serenity.conf).
The content of the configuration file is as follows:
```
serenity {
take.screenshots = FOR_FAILURES
}
headless.mode = false
webdriver {
autodownload = true
base.url = "http://localhost:8080"
driver = firefox
capabilities {
browserName = "firefox"
acceptInsecureCerts = true
}
}
```
The options in the configuration file are self-explanatory.
More information about the configuration can be found in the [Serenity documentation](https://serenity-bdd.github.io/docs/reference/serenity-properties).
In the case of the BDD suite, the test runner expects the web application has been running at specified URL, i.e. the value set in `base.url`.
The web application will not automatically run when we execute the BDD test suite.
Therefore, we have to build and deploy the web application prior to running the tests.
Before running the BDD test suite, run the web application in a shell:
```shell
mvn spring-boot:run
```
Then, run the BDD test suite in a different shell:
```shell
mvn -P bdd verify
```
We can also run the BDD test suite directly on IntelliJ by running the auto-detected `CucumberTestSuite` run configuration.
IntelliJ will automatically run the web application before executing the BDD test suite.
To see the test report generated by the test runner,
open the HTML document located at [`./target/site/serenity/index.html`](./target/site/serenity/index.html).
The report will show information such as the total number of features and their test status.
## Tasks
Your tasks are to write new test scenarios for two existing features that yet to be covered by the BDD test suite.
The two features are: "see motivation message" and "mark a todo item."
At minimum, you need to write **two new test scenarios** for both features.
The test scenarios can be as simple as covering the "positive" and "negative" case that can occur on both features,
or to cover other possible outputs.
### Mandatory Tasks
- [ ] Set up the development environment for the project locally
- Refer to [Setting Up Development Environment](#setting-up-development-environment) section
- [ ] Run the project locally and try the existing features
- Try to add new todo items and mark their completion status
- See how the motivation message is updated based on the number of completed todo items
- [ ] Run the test suites locally, ensure all test passes
- [ ] Write two test scenarios for "see motivation message" feature
- [ ] Write two test scenarios for "mark a todo item" feature
- [ ] Write the required "glue" code to support the new test scenarios
- [ ] Summarise the whole process and write them in a `summary.md`. Write an analysis of what you did and what you learned from this exercise. Please provide screenshot for each test scenario
> Note: You are allowed to modify the production code (i.e. the `src/main/java` directory) to make your test code can obtain the reference to the UI elements in the page.
> For example, you can add a new HTML attribute, CSS class, or CSS id to an element in the page to make it easier to be located.
### Additional Tasks
- [ ] Maintain code coverage greater than or equal to 97%
- [ ] Implement an error handling when posting an empty todo item. Create a test scenario for this error-handling
> Outline:
> - Gherkin format (Given-When-Then) as executable scenarios
> - Glue code, step definitions
> - Screenplay & Page Object pattern
>
> Quotes:
> - Ideally, if all of the acceptance criteria for a feature have been automated and run successfully, you can say that this feature is finished and ready for production.
>
> References:
> - https://livebook.manning.com/book/bdd-in-action-second-edition/chapter-8
> - See chapter 8.5.1 of the BDD reference book to learn how to perform setup & teardown phase in BDD test.
>
> Draft Scenario for additional task: Todo item cannot be empty
>
> - Given Alice is looking at the todo list
> - When she accidentally adds an empty item
> - Then she should be presented with a warning message containing "Todo item cannot be empty"
## License
This project is licensed under the terms of the [MIT license](./LICENSE).