Scala features by its DSL like assertion and testing, it reads like nartual English and is especially friendly for test specfication writer (they don't need to be some expert in computing or programming language).
There are several Test framework that is available for the Scala programming language. this include
Scala Test
JUnit and TestNG
Specs
ScalaCheck
examples of the scala assertion on the element class and its accompanying object is as follow.
package assertionAndUnitTesting.assertions; // file: // elements.scala // package: // assertionAndUnitTestting.elements // description: // in this post, we will examine the scala assertions, the very basic construct which allows us to do pre/post condition check object Element { private class ArrayElement(val contents: Array[String]) extends Element private class LineElement( s : String) extends Element { def contents : Array[String] = Array(s) override def height : Int = 1 override def width : Int = s.length } private class UniformElement( chr : Char, override val width : Int, override val height :Int ) extends Element { // ch * width will fail, // and the error message is not clear - type mismatch (expect String, Int provided) the REPL need to improve // on it error handling. private val line : String = chr.toString * width override def contents : Array[String] = Array.fill(height)(line) } def elem(contents: Array[String]) : Element = new ArrayElement(contents) def elem(s : String) : Element = new LineElement(s) def elem(chr : Char, width : Int, height : Int) : Element= new UniformElement(chr, width, height) } import Element.elem // contents: not defined, you need to declare your class as "abstract" // abstract class Element { def contents : Array[String] def height : Int = contents.length def width = if (contents.length ==0 ) 0 else contents(0).length def beside(that : Element) : Element = { val this1 = this heighten that.height val that1 = that heighten this.height elem ( for ((line1, line2) <- this1.contents zip that1.contents) yield (line1 + line2) ) } def above(that : Element) : Element = { val this1 = this widen that.width val that1 = that widen this.width assert(this1.width == that1.width) // assert that this1.width is equal to that1.width before above is called on the real contents. elem(this1.contents ++ that1.contents) } def widen(w : Int) : Element = if (w <= width) this else { val left = elem(' ', (w - width) /2 , height) val right = elem(' ', (w - width + left.width), height) left beside this beside right } ensuring (w <= _.width) // ensure after widen, parameter w is less than the widen one. def heighten(h : Int) : Element = if (h <= height) this else { val top = elem(' ', width, (h - height) / 2) val bottom = elem(' ', width, (h - height + top.height)) top above this above bottom } override def toString = contents mkString "\n" }
ScalaTest offers some basic means to write test in Scala and also it provides several bridges to other test framework such as Junit and TestNG..
a very straightfoward test case in ScalaTest is as follow.
// file: // scalatest_testsuite.scala // package: // assertionAndUnitTesting.testing.scalatests package assertionAndUnitTesting.testing.scalatests import org.scalatest.Suite // import assertionAndUnitTesting.testing.scalatests import assertionAndUnitTesting.assertions._ import assertionAndUnitTesting.assertions.Element._ // extends the org.scalatest.Suite and define test method with testXXX names class ElementSuite extends Suite { def testUniformElement() { val ele = elem('x', 2, 3 ) assert(ele.width == 2) } }
and scalatest also provides a different style of testing, it also provide a FunSuite, where you can override the test method and supply the a function value rather than methods.
// file: // scalatest_funsuite.scala // package: // assertionAndUnitTesting.testing.scalatests package assertionAndUnitTesting.testing.scalatests import org.scalatest.FunSuite import assertionAndUnitTesting.assertions._ import assertionAndUnitTesting.assertions.Element._ // test is passed in as a by-name parameter to the test method class ElementSuite extends FunSuite { test("elem result should have passed width") { val ele = elem('x', 2, 3) assert(ele.width == 2) } }
in this post, we will going to examine some of the common used test framework and show some guidelines on how to write Unit Test for Scala programming language.
to use the JUnit, the following example shows that you can run junit scala test code with the Junit test runner.
// file // junits_testcase.scala package assertionAndUnitTesting.testing.junits import junit.framework.TestCase import junit.framework.Assert.assertEquals import junit.framework.Assert.fail import assertionAndUnitTesting.assertions.Element.elem; class ElementTestCase extends TestCase { def testUnitformElement() { val ele = elem('x', 2, 3) assertEquals(2, ele.width) assertEquals(3, ele.height) try { elem('x', -2, 3) fail() } catch { case e : IllegalArgumentException => { println("an IllegalArgumentException") } } } }and you can also take advantage of the scala conciseness like assertion and others, you can use the JunitWrapperSuite offered by the SCala test.
// file // junits_junit3suite.scala package assertionAndUnitTesting.testing.junits import junit.framework.TestCase import junit.framework.Assert.assertEquals import junit.framework.Assert.fail import assertionAndUnitTesting.assertions.Element.elem; import org.scalatest.junit.JUnit3Suite class ElementSuite extends JUnit3Suite { def testUniformElement() { val ele = elem('x', 2, 3 ) assert(ele.width == 2) expect (3) { ele.height } intercept[IllegalArgumentException] { elem('x', -2, 3) } } }
the way how it report the error is less informative, you might get an error message such as "3 did not equal to 2" in the failure reports.
ScalaTest gives you the following construct to report meaningful infomraiton on the error/reports.
an example is shown as follow.
// file // scalatest_informative_failure_report.,scala // package package assertionAndUnitTesting.testing.scalatests import org.scalatest.Suite import assertionAndUnitTesting.assertions._ import assertionAndUnitTesting.assertions.Element._ class InformativeSuite extends Suite { def testExpect() { val ele = elem('x', 2, 3) // expect(2) { // expect has been deprecated expectResult(2) { ele.width } } def testInterceptException() { intercept[IllegalArgumentException] { // throw throw new IllegalArgumentException("Argument should not be null") elem('x', -2, 3 ) } } }
Junit is a very successful frameowrk of writing test for java classes, and as we already know that scala will be running on the Java runtime, and scala will compile into classes which can be understood by the junit runtime.
// file // junits_testcase.scala package assertionAndUnitTesting.testing.junits import junit.framework.TestCase import junit.framework.Assert.assertEquals import junit.framework.Assert.fail import assertionAndUnitTesting.assertions.Element.elem; class ElementTestCase extends TestCase { def testUnitformElement() { val ele = elem('x', 2, 3) assertEquals(2, ele.width) assertEquals(3, ele.height) try { elem('x', -2, 3) fail() } catch { case e : IllegalArgumentException => { println("an IllegalArgumentException") } } } }
Also, ScalaTest provides a Junit test wrapper - JUnit3Suite, with which you can leverage the scaltest's conciseness.
// file // junits_junit3suite.scala package assertionAndUnitTesting.testing.junits import junit.framework.TestCase import junit.framework.Assert.assertEquals import junit.framework.Assert.fail import assertionAndUnitTesting.assertions.Element.elem; import org.scalatest.junit.JUnit3Suite class ElementSuite extends JUnit3Suite { def testUniformElement() { val ele = elem('x', 2, 3 ) assert(ele.width == 2) expect (3) { ele.height } intercept[IllegalArgumentException] { elem('x', -2, 3) } } }
// file // testng_elementtests.scala // package // assertionAndUnitTesting.testing.testng package assertionAndUnitTesting.testing.testng import org.testng.annotations.Test import org.testng.Assert.assertEquals import assertionAndUnitTesting.assertions.Element.elem class ElementTests { @Test def verifyUniformElement() { val ele = elem('x', 2, 3) assertEquals(ele.width, 2) assertEquals(ele.height, 3) } @Test( expectedExceptions = Array(classOf[IllegalArgumentException]) ) def elementShoudThrowIAE() { elem('x', -2, 3) } }
// file // testng_scalawrapper.scala // package // assertionAndUnitTesting.testing.testng package assertionAndUnitTesting.testing.testng import org.testng.annotations.Test import org.testng.Assert.assertEquals import org.scalatest.testng.TestNGSuite import assertionAndUnitTesting.assertions.Element.elem class ElementSuite extends TestNGSuite { @Test def verifyUniformElement() { val ele = elem('x', 2, 3) assertEquals(ele.width, 2) expect(3) { ele.height } intercept[IllegalArgumentException] { elem('x', -2, 3) } } }
// file // specification_flatspecification.scala // package: // assertionAndUnitTesting.testing.specifications package assertionAndUnitTesting.testing.specifications import assertionAndUnitTesting.assertions.Element.elem; import org.scalatest.FlatSpec import org.scalatest.matchers.ShouldMatchers class ElementSuite extends FlatSpec with ShouldMatchers { "A uniformElement" should "having a width equal to the passed value" in { val ele = elem('x', 2, 3) ele.width should be (3) } it should "have a height equal to the passed value" in { val ele = elem('x', 2, 3) ele.height should be (3) } it should "throw an IAE if passed a negative width" in { evaluating { elem('x', -2, 3) } should produce [IllegalArgumentException] } }This is with the ShouldMatcher, and you can re-write the code to have the MustMatcher.
// file // specification_mustmatcher.scala // package: // assertionAndUnitTesting.testing.specifications package assertionAndUnitTesting.testing.specifications import assertionAndUnitTesting.assertions.Element.elem; import org.scalatest.FlatSpec import org.scalatest.matchers.ShouldMatchers import org.scalatest.matchers.MustMatchers class MustElementSuite extends FlatSpec with MustMatchers { "A uniformElement" should "having a width equal to the passed value" in { val ele = elem('x', 2, 3) ele.width must be >= 0 ele.width must be (3) } it should "have a height equal to the passed value" in { val ele = elem('x', 2, 3) // ele must have height 3 // -overloaded method value must with override ... cannot be applied to Element. var arr = new Array(3) arr must have length 3 var map = Map('a' -> 1, 'b' -> 2) map must contain key 'c' ele.height must be (3) } it should "throw an IAE if passed a negative width" in { evaluating { elem('x', -2, 3) } must produce [IllegalArgumentException] } }There is a spec testing framework, which is similar to the MustMatcher and the ShouldMatcher , but it has different syntax, let' check this out.
// file // specification_specframework.scala // package: // assertionAndUnitTesting.testing.specifications package assertionAndUnitTesting.testing.specifications import org.specs._ import assertionAndUnitTesting.assertions.Element.elem; import org.scalatest.FlatSpec import org.scalatest.matchers.ShouldMatchers class ElementSpecification extends Specification { "A uniformElement" should { "having a width equal to the passed value" in { val ele = elem('x', 2, 3) ele.width must be_==(3) } "have a height equal to the passed value" in { val ele = elem('x', 2, 3) ele.height must be_==(3) } "throw an IAE if passed a negative width" in { elem('x', -2, 3) must throwA[IllegalArgumentException] } } }
// file // specification_propertybased.scala // package: // assertionAndUnitTesting.testing.propertybased package assertionAndUnitTesting.testing.propertybased import assertionAndUnitTesting.assertions.Element.elem; import org.scalatest.WordSpec import org.scalatest.prop.Checkers import org.scalacheck.Prop._ // ==> is the "implication operator", which means if the // left is true, then the right must hold true class ElementSpecification extends WordSpec with Checkers { "elem result" must { "have passed with " in { check ((w : Int) => w > 0 ==> (elem('x', w, 3).width == w)) } "have passed height " in { check ((h : Int) => h > 0 ==> (elem('x', 2, h).height == h)) } } }
[PLACEHOLDER]:
This is a placholder we will come back to it later.
References:
specs framework
ScalaCheck