Fakultas Ilmu Komputer UI

Skip to content
Snippets Groups Projects
README.md 12.5 KiB
Newer Older
Daya Adianto's avatar
Daya Adianto committed
# Sitodo (PMPL Variant)

[![pipeline status](https://gitlab.cs.ui.ac.id/pmpl/examples/sitodo-pmpl/badges/main/pipeline.svg)](https://gitlab.cs.ui.ac.id/pmpl/examples/sitodo-pmpl/-/commits/main)
[![coverage report](https://gitlab.cs.ui.ac.id/pmpl/examples/sitodo-pmpl/badges/main/coverage.svg)](https://gitlab.cs.ui.ac.id/pmpl/examples/sitodo-pmpl/-/commits/main)
Daya Adianto's avatar
Daya Adianto committed

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.
Daya Adianto's avatar
Daya Adianto committed

## 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
Daya Adianto's avatar
Daya Adianto committed

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
Daya Adianto's avatar
Daya Adianto committed
-  [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
Daya Adianto's avatar
Daya Adianto committed

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.

### Build & Run
Daya Adianto's avatar
Daya Adianto committed

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.

### Running Example
Daya Adianto's avatar
Daya Adianto committed

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).
Daya Adianto's avatar
Daya Adianto committed

## 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
Daya Adianto's avatar
Daya Adianto committed

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.
### Glue Code

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`.

### Execute Test Suite & Reporting

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
Adrika Novrialdi's avatar
Adrika Novrialdi committed
- [ ] 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%
Adrika Novrialdi's avatar
Adrika Novrialdi committed
- [ ] 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"
Daya Adianto's avatar
Daya Adianto committed
## License

This project is licensed under the terms of the [MIT license](./LICENSE).