Easy BDD with (Java) Spectrum?

This article is the 14th day article of Apresso Advent Calendar 2017.

What is BDD

Behavior Driven Development, an abbreviation for Behavior Driven Development. It appears in the context of improving software development methods. This is a development method that is closer to the requirements analysis phase than TDD (Test Driven Development).

The following articles will help you to understand what TDD and BDD mean in software development methods. Behavior-Driven Development-Steps from the Waterfall Model

The point is to focus on features and go through the cycle of requirements analysis, design, coding, and testing, and thereby develop and release faster (agile).

Java BDD framework

Looking at Java's BDD framework, it seems that there are many.

Cucumber A standard BDD framework that can be used in various languages, not limited to Java. The advantage is that developers, testers, and business people (business folks) can share knowledge. Functions (behaviors) are described in a unique language called Gherkin.

By the way, Gherkin's Japanese reading is "Gherkin", which is a small cucumber to be pickled. Honke site

JBehave This seems to be Java only, but it seems to be a framework as popular as Cucumber. The feature is that functions (tests) can be described in Sinario (scenario, user story), Given (prerequisite), When (test case), Then (behavior as it should be) format. Honke site

Example Sinario: "Test for stock price alerts. Test to determine if a given stock price exceeds a threshold." Given: "The stock price threshold is 1500 yen" When: "When the stock price is 500 yen" Then: "Alert status is OFF" When: "When the stock price is 1600 yen" Then: "Alert status is ON"

JGiven This is described in detail in Article written last year by @enk, the same Apresso engineer, so I will leave the explanation to that.

It seems that the advantage is that all the work is completed only with Java.

Is it a tool that can write JUnit with the idea of Given, When, Then like JBehave?

Spectrum This is the Java BDD framework I would like to introduce this time. I think it's more like JGiven. GitHub

Feature

  1. Can be written only in Java (no separate file for behavior is required)
  2. Seamlessly integrate with existing JUnit tools and IDEs
  3. Can be described in either Specification style or Gherkin style
  4. You can mix Junit tests and Spectrum tests

Why Spectrum

This is because it is easy to introduce.

Cucumber and JBehave describe the behavior in a text file and finally incorporate it into JUnit. This is probably because the last of the three characters Cucumber envisions (developer, tester, business person, product owner?) Will also participate. It might be good to turn BDD "properly" in large-scale development. There are many things to prepare and remember, and I think that the threshold is high for everyone.

JGiven is a more developer-friendly framework that allows you to express your behavior in Java code. It focuses on developers writing tests with the idea of BDD. Of course, the test report is also output in a format that focuses on the function, so characters other than the developer can also benefit. However, I have to create State, Action, and Outcome classes in addition to the test class, and it seems difficult (although I have not confirmed) to mix it with existing tests.

Since the substance of Spectrum is an extension of JUit, there is no need to create a class other than the test class, and since it can be mixed with existing JUnit tests, it can be partially introduced.

Introduction method

Add the spectrum jar file to your classpath.

Requirements

--Java 8 (to use lambda) --JUnit (because it is an extension of JUnit)

Add dependency

Gradle Add the following line to the dependencies of build.gradle.

For java-library

testImplementation 'com.greghaskins:spectrum:1.2.0'



 Otherwise

#### **`testCompile 'com.greghaskins:spectrum:1.2.0'`**

Maven Add the following to the dependencies of pom.xml.

<dependency>
    <groupId>com.greghaskins</groupId>
    <artifactId>spectrum</artifactId>
    <version>1.2.0</version>
    <scope>test</scope>
</dependency>

other than that

Download it from the Maven Central Repository (https://mvnrepository.com/artifact/com.greghaskins/spectrum) and add it to your classpath.

Sample code

I prepared the code to be tested, created tests in 3 types of Spec format, Gherkin format, and Junit format, and compared them.

Code to be tested

Prepare the following test target.

StockWatcher.java


public class StockWatcher {
	private int threshold;
	
	public int getThreshold() {
		return threshold;
	}

	public void setThreshold(int threshold) {
		this.threshold = threshold;
	}
	
	public boolean getAlert(int stockPrice) {
		return threshold <= stockPrice;
	}
}

Spec format test

If you write a test in Spec format, you can write it as follows.

StockWatcherSpecTest.java


import static org.junit.Assert.*;
import static com.greghaskins.spectrum.dsl.specification.Specification.*; //Spectrum-specific

import java.util.function.Supplier;
import org.junit.runner.RunWith;
import com.greghaskins.spectrum.Spectrum; //Spectrum-specific

/**
 *Specification format test
 * describe -You can write tests in it format
 */
@RunWith(Spectrum.class)
public class StockWatcherSpecTest {{
	//Describe the specification with describe
	describe("Test stock alerts. A test to determine if a given stock price exceeds a threshold.", ()->{
		//describe can be nested
		describe("Set the stock price threshold to 1500 yen", ()->{
			//You can create a test target with let
			Supplier<StockWatcher> stockWatcher = let(() -> {
				StockWatcher w = new StockWatcher();
				w.setThreshold(1500);
				return w;
				});
			describe("When the stock price is 500 yen", ()->{
				//it corresponds to the test case
				it("Alert status is OFF", () -> {
					assertFalse(stockWatcher.get().getAlert(500));
				});
			});
			describe("When the stock price is 1600 yen", ()->{
				it("Alert status is ON", () -> {
					assertTrue(stockWatcher.get().getAlert(1600));
				});
			});
		});
	});
}}

When I run it in eclipse, it looks like this. spec-eclipse.PNG

Gherkin-style test

If you write the test in Gherkin format, you can write it as follows.

StockWatcherGerkinTest.java


import static org.junit.Assert.*;
import static com.greghaskins.spectrum.dsl.gherkin.Gherkin.*; //Spectrum-specific

import org.junit.runner.RunWith;
import com.greghaskins.spectrum.Spectrum; //Spectrum-specific
import com.greghaskins.spectrum.Variable;

/**
 *Gherkin-style test
 * feature, scenario, given, when,You can write tests in then format
 */
@RunWith(Spectrum.class)
public class StockWatcherGherkinTest {{
	feature("Test stock alerts.", () -> {
		scenario("A test to determine if a given stock price exceeds a threshold.", () -> {
			StockWatcher w = new StockWatcher();
			final Variable<Boolean> alert = new Variable<>();
			
			given("Set the stock price threshold to 1500 yen", () -> {
				w.setThreshold(1500);
			});
			
			when("When the stock price is 500 yen", () -> {
				alert.set(w.getAlert(500));
			});
			
			then("Alert status is OFF", () -> {
				assertFalse(alert.get());
			});
		});
		scenario("A test to determine if a given stock price exceeds a threshold.", () -> {
			StockWatcher w = new StockWatcher();
			final Variable<Boolean> alert = new Variable<>();
			
			given("Set the stock price threshold to 1500 yen", () -> {
				w.setThreshold(1500);
			});
			
			when("When the stock price is 1600 yen", () -> {
				alert.set(w.getAlert(1600));
			});
			
			then("Alert status is OFF", () -> {
				assertTrue(alert.get());
			});
		});
	});
}}

When I run it in eclipse, it looks like this. gherkin-eclipse.PNG

Traditional (JUit) test

With the conventional writing method, you can write as follows.

StockWatcherJunitTest.java


import static org.junit.Assert.*;

import org.junit.Test;

/**
 *Traditional JUnit format testing
 */
public class StockWatcherJunitTest {
	@Test
public void When the stock price threshold is 1500 yen_The alert status is OFF for a stock price of 500 yen.() {
		StockWatcher w = new StockWatcher();
		w.setThreshold(1500);
		
		assertFalse(w.getAlert(500));
	}
	
	@Test
public void When the stock price threshold is 1500 yen_The alert status is ON for the stock price of 1600 yen.() {
		StockWatcher w = new StockWatcher();
		w.setThreshold(1500);
		
		assertTrue(w.getAlert(1600));
	}
}

When I run it in eclipse, it looks like this. junit-eclipse.PNG

Test report

When I generated the test report from Gradle, I got something like the following:

report1.PNG

In the case of Spec format, only describe paired with it seems to be treated as a test class. Gherkin-style cases are treated as test classes on a scenario-by-scenario basis.

The result in Spec format. report-spec1.PNG

report-spec2.PNG

The result in Gherkin format. report-gherkin.PNG

This is the result in JUnit format. report-junit.PNG

Impressions

Good point

You can change the way you write tests to BDD style without changing the traditional (JUnit) mechanism. It can be partially introduced and gradually incorporate BDD.

Unfortunately

Although the specifications can be described in Japanese sentences, the report does not correspond to the source code sentences. For example, sentences written outside the nested describe and sentences written in the feature are not output to the report. In addition, the longer the text, the less you can follow the links in the report. The cause is that the character string written in describe etc. is used for the file name of the HTML file of the report, and if the sentence is long, the limitation of the length of the file name of the OS may be exceeded. (See the figure below)

filename.PNG

In the Gherkin format, given, when, and then are treated as test cases, which increases the amount of results. (Given, when will of course succeed.) When outputting to a report, test cases are sorted and displayed in ascending alphabetical order, so if you write multiple given, when, then in the same scenario, only all givens will be displayed. It is displayed first and is hard to see. Even if there is only one combination of given, when, then, the order is given, then, when, which is still difficult to see. It's far from JGiven's report.

If the report does not correspond to the source code description, it will be difficult for non-developer parties to participate in BDD.

Summary

Spectrum is a framework that allows you to create test scripts in BDD style without changing the traditional JUnit test mechanism. I thought it would be good to introduce it on a trial basis and gradually practice BDD.

However, I find it difficult to actually turn BDD because the output of the test report does not fully correspond to the source code description: sob :.

Reference site

Site that covers BDD frameworks regardless of specific language (English)

Recommended Posts

Easy BDD with (Java) Spectrum?
100% Pure Java BDD with JGiven (Introduction)
Easy database access with Java Sql2o
Easy to trip with Java regular expressions
Easy to make LINE BOT with Java Servlet
Install java with Homebrew
Change seats with java
Install Java with Ansible
Comfortable download with JAVA
Switch java with direnv
Download Java with Ansible
Let's scrape with Java! !!
Build Java with Wercker
Endian conversion with JAVA
Easy microservices with Spark Framework!
Use Lambda Layers with Java
Java multi-project creation with Gradle
Getting Started with Java Collection
Java Config with Spring MVC
Basic Authentication with Java 11 HttpClient
Let's experiment with Java inlining
Run batch with docker-compose with Java batch
[Template] MySQL connection with Java
Rewrite Java try-catch with Optional
Install Java 7 with Homebrew (cask)
[Java] JSON communication with jackson
Java to play with Function
Try DB connection with Java
Enable Java EE with NetBeans 9
[Java] JavaConfig with Static InnerClass
Try gRPC with Java, Maven
Let's operate Excel with Java! !!
Version control Java with SDKMAN
RSA encryption / decryption with java 8
Paging PDF with Java + PDFBox.jar
Sort strings functionally with java
Object-oriented (java) with Strike Gundam
[Java] Content acquisition with HttpCliient
Java version control with jenv
Troubleshooting with Java Flight Recorder
Streamline Java testing with Spock
Connect to DB with Java
Connect to MySQL 8 with Java
Error when playing with java
Using Mapper with Java (Spring)
Java study memo 2 with Progate
Getting Started with Java Basics
Easy web scraping with Jsoup
Easy library introduction with Maven!
Seasonal display with Java switch
Use SpatiaLite with Java / JDBC
Study Java with Progate Note 1
Compare Java 8 Optional with Swift
HTML parsing with JAVA (scraping)
Run Java VM with WebAssembly
Screen transition with swing, java
Java unit tests with Mockito
[Java 8] Duplicate deletion (& duplicate check) with Stream
Create an immutable class with JAVA
Java lambda expressions learned with Comparator
Easy JDBC calls with Commons DbUtils