📜 ⬆️ ⬇️

A little introduction to Scalatest

Scalatest is an application testing framework that supports different test-writing styles and integrates seamlessly with other JVM tools, including IDE and maven.

Each of the supported testing styles in Scalatest is designed to be used for specific purposes. To use each of the testing styles, you need to create a class that will implement the trait in which this testing style is defined. The chosen style determines only what the test declarations look like; all other features of the framework will work the same regardless of which test style was chosen. The authors recommend using FlatSpec for unit tests and integration testing, and FeatureSpec for acceptance testing, so I’ll point out a couple of other styles just for example:

FlatSpec

FlatSpec is a good step forward for teams that want to move from using xUnit and other similar frameworks to using BDD, FlatSpec is a DSL that allows you to write tests as close as possible to writing the behavior specification of the class under test.
import org.scalatest.FlatSpec class SetSpec extends FlatSpec { "An empty Set" should "have size 0" in { assert(Set.empty.size == 0) } it should "produce NoSuchElementException when head is invoked" in { intercept[NoSuchElementException] { Set.empty.head } } } 


FeatureSpec

FeatureSpec aims to create acceptance tests, making it easier for programmers working with non-programmers to describe acceptance requirements.
 import org.scalatest._ class TVSet { private var on: Boolean = false def isOn: Boolean = on def pressPowerButton() { on = !on } } class TVSetSpec extends FeatureSpec with GivenWhenThen { info("As a TV set owner") info("I want to be able to turn the TV on and off") info("So I can watch TV when I want") info("And save energy when I'm not watching TV") feature("TV power button") { scenario("User presses power button when TV is off") { Given("a TV set that is switched off") val tv = new TVSet assert(!tv.isOn) When("the power button is pressed") tv.pressPowerButton() Then("the TV should switch on") assert(tv.isOn) } scenario("User presses power button when TV is on") { Given("a TV set that is switched on") val tv = new TVSet tv.pressPowerButton() assert(tv.isOn) When("the power button is pressed") tv.pressPowerButton() Then("the TV should switch off") assert(!tv.isOn) } } } 

')
Funsuit

FunSuite is designed for teams that previously used xUnit, the use of this style allows you to comfortably switch to Scalatest and take advantage of BDD. Usage example:
 import org.scalatest.FunSuite class SetSuite extends FunSuite { test("An empty Set should have size 0") { assert(Set.empty.size == 0) } test("Invoking head on an empty Set should produce NoSuchElementException") { intercept[NoSuchElementException] { Set.empty.head } } } 


Funspec

FunSpec Scalatest authors suggest using those who previously used tools like RSpec for Ruby
 import org.scalatest.FunSpec class SetSpec extends FunSpec { describe("A Set") { describe("when empty") { it("should have size 0") { assert(Set.empty.size == 0) } it("should produce NoSuchElementException when head is invoked") { intercept[NoSuchElementException] { Set.empty.head } } } } } 


WordSpec

Also, for users of specs and specs2, the authors of scalatest suggest using WordSpec treit, which they claim is the most natural way to port tests from specs to scalatest.
 import org.scalatest.WordSpec class SetSpec extends WordSpec { "A Set" when { "empty" should { "have size 0" in { assert(Set.empty.size == 0) } "produce NoSuchElementException when head is invoked" in { intercept[NoSuchElementException] { Set.empty.head } } } } } 


The title of each test in FlatSpec should be a sentence that describes the behavior being tested and consists of the subject, the keyword should must or can and the end of the sentence. the title is followed by the word in and the body of the test itself in curly brackets. Here is a complete test example:

 import collection.mutable.Stack import org.scalatest._ class StackSpec extends FlatSpec { "A Stack" should "pop values in last-in-first-out order" in { val stack = new Stack[Int] stack.push(1) stack.push(2) assert(stack.pop() == 2) assert(stack.pop() == 1) } it should "throw NoSuchElementException if an empty stack is popped" in { val emptyStack = new Stack[String] intercept[NoSuchElementException] { emptyStack.pop() } } } 


Assertions

In each style, 3 asserts are available by default:


Scalatest defines its own assert method, which hides the method defined in the predef and throws a TestFailedException exception instead of the standard AssertionError. However, the assert method does not allow a distinction between an expected and an actual result. This distinction can be made using the assertResult method:
 val a = 5 val b = 2 assertResult(2) { a - b } 


in that case, if the actual result does not match the expected result, the message in the TestFailedException exception will be “Expected 2, but got 3.”.
The intercept method allows you to test expected exceptions:
 val s = "hi" intercept[IndexOutOfBoundsException] { s.charAt(-1) } 


since it returns the exception that it caught, it can also be used to check messages or other information added to this exception:
 intercept[IndexOutOfBoundsException](s charAt -1).getMessage should be == "..." 


Matchers

In the previous example, you can see the use of the word be. At scalatest this is also one of the keywords that can be used if you connect the mixin Matchers to the class that implements the test. Since the scalatest is very close to the natural language of DSL, the further code under this heading is given almost without explanation.

With the help of this trait, you can write more approximate to the natural language specifications:
Equality

 4 must equal(4) "foo" must equal("foo") List("foo", "bar", "baz") must equal(List("foo", "bar", "baz")) (1, "foo") must equal((1, "foo")) 

Object size, object length

 "foo" must have length (3) List(1, 2, 3, 4) must have length (4) Array('A', 'B') must have length (2) List(1, 2, 3, 4) must have size (4) Array('A', 'B') must have size (2) 

String checking

 "foobarbaz" must startWith("foo") "foobarbaz" must endWith("baz") "foobarbaz" must include("bar") "foobarbaz" must startWith regex ("f[o]+") "foobarbaz" must endWith regex ("[ba]{2}z") "foobarbaz" must include regex ("foo[\\w]{3}baz") "foobarbaz" must fullyMatch regex ("\\w{1}oobarbaz") 

Number check

 7 must be < (8) 7 must be > (0) 6 must be <= (7) 7 must be >= (6) 13.43 must equal(13.43) 13.43 must be(13.4 plusOrMinus 0.4) 

Check boolean properties

 List[Int]() must be('empty) //  list.isEmpty new File("/tmp") must be('directory) //  file.isDirectory 

Collections

 List(1, 2, 3, 4) must contain(2) Array("foo", "bar", "baz") must contain("bar") var users = Map(1 -> "Joe", 2 -> "Lisa", 3 -> "Dr. Evil") users must contain key (2) users must contain value ("Dr. Evil") 

Class properties

 case class Recipe(name: String, ingredients: List[String], bakingMinutes: Int) val cookieRecipe = Recipe("cookieRecipe", List("Flour", "Sugar", "Eggs", "Love"), 30) cookieRecipe must have( 'name("cookieRecipe"), 'ingredients(List("Flour", "Sugar", "Eggs", "Love")), 'bakingMinutes(30) ) 

Connection of checks by logical functions

Also, checks can be connected using logic functions and / or, but it is important not to forget to use brackets, so the example users must have size (3) and contain key (3) will not work correctly.
 users must (have size (3) and contain key (3)) users must (contain value ("Mr. X") or contain value ("Joe")) 


The article does not yet consider the many features of this wonderful framework, such as using mock objects or using Selenium, but even using only the features shown allows you to write beautiful and easy to understand tests that are easy to read and tests as close as possible to the degree of expressiveness of the specification code.




www.scalatest.org - project site

Source: https://habr.com/ru/post/209578/


All Articles