PEAT Online Course -
How To Improve Your Personal Performance in Java work Technology

  • YOU + CONTROL
  • Focus
  • Autonomy
  • Proficiency
  • Purpose
  • Covid-19!!!
  • Deep Hidden Meaning
  • FREE updates
GET 75% OFF NOW
Your Promo code: TECHLAYOFF
Exclusively on
VIMEO ON-DEMAND

Scalafication of an Equity Quote Application Part 2

23 July 2011 2 comments

9 minutes

1834

In Part 1 of this article, we discussed the Java language form of an exercise project. The task was to create an equity quote application that retrieved stock prices from a public web service Yahoo! Finance.

Let me suggest a really good process of adopting Scala inside the organisation: take the unit tests written in Java and port them to Scala. The Java implementation does not change and one can learn Scala principles by applying test first and test driven principle.
In the twenty tens, as a modern software practitioner, you must be familiar with JUnit and also the Hamcrest matchers, which are unit test framework by Kent Beck and fluent assertion matchers respectively. The pun was deliberately intended as you will read in the rest of this article.

Just because you start writing Scala does not mean that now you have to give up unit testing (JUnit or TestNG). You can also use Hamcrest Matchers directly from Scala. For example here a unit test:

import org.junit._
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers._

@Test
class SimpleTest  {
     def shouldVerifyTheEssence() {
           val expected = List( 1,1,2,3,5,8 ) 
           val actual = flatten( List(List(1, 1), 2, List(3, List(5, 8)))) )
           assertThat( actual, is(expected )
     }
}

Notice, that you can use annotations in Scala as well. Of course, the immutable variable references are unnecessary, however the purpose of the unit test should be clear to read. Your pairing partner should be able to understand your intent and can agree with you that it is concise. The method flatten reduces a nest list collection to a single list collection. The Hamcrest matchers are useful for fluent API programming, such that the code almost reads like an English description. For more information on Hamcrest, see the tutorial.

Let me introduce you to Scala Test, which is a fluent API testing framework written by Bill Venners, and it can be called from JUnit and it has support for behaviour driven design (BDD). You can use the assertion API from the JUnit inside a ScalaTest like this:

import org.scalatest.FlatSpec
import org.scalatest.matchers.ShouldMatchers
import org.junit.Assert._
import org.scalatest.junit.JUnitRunner
import org.junit.runner.RunWith

@RunWith(classOf[JUnitRunner])
class FibonacciSeriesSpec extends FlatSpec with ShouldMatchers {

  "A Fibonacci function" should "establish a mathematical series" in {
        val expected = List( 0, 1,1,2,3,5,8,13,21, 34, 55, 89, 144, 233, 377, 610, 987 ];
        expected.foreach( x => assertEquals( x, fibonacci(x) )
  }

}

Behind the scenes of this examples are a few bits of knowledge:

  • This is the short form of running a JUnit test with ScalaTest, because I prefer to use the JUnit Runner and because it avoids writing the companion object. With JUnit (or TestNG) runners the test can be launched from popular Java tools like SBT, Maven or an IDE.
  • The specification is essentially a JRuby (RSpec) syntax in keeping with the BDD style (See Dan North on Introduction BDD)
  • Demonstrates that domain specific language can be written in Scala.
  • A fluent API in Scala can be supported by Scala powerful implicit conversions
  • The unit tests are readable, the expected behaviour of the target can be literally described in the language. Once again, it about Scala’s exceptional ability to allow developers to express their intent in a concise fashion.
  • ScalaTest allows you to reuse traditional style of unit testing too. You can find example of a JUnit 4 style in Scala here.

There is another Scala testing framework for BDD called Specification, which can be found here
https://code.google.com/p/specs. Here is an example for writing an executable specification with this framework very quickly.

import org.specs._

class MySpec extends SpecificationWithJUnit {
  "This wonderful system" should {
    "save the world" in {
      val list = Nil
      list must beEmpty
      println ("Done with the specification")
    }
  }
}

(UPDATED: This framework has been superseded by second version called Specs 2 https://specs2.org/. Thanks to Eric Torreborre for the corrections.)

With both ScalaTest and Specification, it is possible to use a mixture of the fluent and traditional assertion API in the unit tests. The quote retriever examples that I developed used ScalaTest, I prefer to use the BDD style rather than the traditional JUnit style, because it reads easier to a non-coder (or a line manager ;-).

ScalaTest has a few specification styles that support alternative BDD styles. There are the FeatureSpec, FlatSpec, and my own favourite WordSpec. These styles are mixed into tests as Scala traits. In order to complete the BDD style you normally mix in the ShouldMatchers, and therefore you do not need the Java styled JUnit assertion classes or the Hamcrest Macthers.

This is an example of the FeatureSpec style.

import org.scalatest.Spec
import org.scalatest.matchers.ShouldMatchers
import scala.collection.mutable.Stack

class StackSpec extends Spec with ShouldMatchers {

  describe("A Stack") {

    describe("(when empty)") {

      val stack = new Stack[Int]

      it("should be empty") {
        stack should be ('empty)
      }

      it("should complain when popped") {
        evaluating { stack.pop() } should produce [NoSuchElementException]
      }
    }
  }
}

This is an example of the WordSpec style.

import org.scalatest.WordSpec
import org.scalatest.matchers.ShouldMatchers
import scala.collection.mutable.Stack

class StackSpec extends WordSpec with ShouldMatchers {

  "A Stack" when {
    "empty" should {
      val stack = new Stack[Int]

      "be empty" in {
        stack should be ('empty)
      }

      "add one item and remove one item" in {
          stack.push(1974)
          stack should not be ('empty)
          stack.pop() should be 1974
          stack should be ('empty)
      }

      "complain when popped" in {
        evaluating { stack.pop() } should produce [NoSuchElementException]
      }
    }
  }
}

In the Java world, I discovered years ago, the Mockito framework as a great mocking tool. Did you know that you can use Mockito in a Scala as well, and therefore with ScalaTest? Here is how. Here follows the first the unit test that uses ScalaTest to verify the operation of the stock quote retriever.

package uk.co.xenonique.stockquoteapp_scala

import org.scalatest.WordSpec
import org.scalatest.mock.MockitoSugar
import org.scalatest.junit.JUnitRunner
import org.scalatest.matchers.ShouldMatchers
import org.mockito.Mockito._
import org.junit.runner.RunWith

@RunWith(classOf[JUnitRunner])
class StockQuoteAppTest extends WordSpec with ShouldMatchers with MockitoSugar {

  "The quote retriever" should {
    "get stock quotes" in {
      val repo: QuoteRepository = new QuoteRepositoryKeyValueStore()
      val mockRetriever: QuoteRetriever = mock[ QuoteRetriever ]

      val expected1 = new StockQuote("APPL", "100.24", "100.20")
      when( mockRetriever.getStockQuote( expected1.symbol )).thenReturn(expected1)

      val expected2 = new StockQuote("PILG", "725.96", "721.32")
      when( mockRetriever.getStockQuote( expected2.symbol )).thenReturn(expected2)

      val app = new StockQuoteApp( mockRetriever, repo )

      app.findAndUpdateStockQuote(expected1.symbol)
      repo.get( expected1.symbol).get should be === expected1 

      app.findAndUpdateStockQuote(expected2.symbol)
      repo.get( expected2.symbol).get should be === expected2 

      repo.isEmpty() should be === false 
      repo.size() should be === 2

      verify(mockRetriever).getStockQuote(expected1.symbol)
      verify(mockRetriever).getStockQuote(expected2.symbol)
    }
  }

  "The quote retriever" should {
    "get stock quotes with one changed" in {

      val repo: QuoteRepository = new QuoteRepositoryKeyValueStore()
      val mockRetriever: QuoteRetriever = mock[QuoteRetriever]

      val expected1 = new StockQuote("APPL", "100.24", "100.20")
      when( mockRetriever.getStockQuote( expected1.symbol )).thenReturn(expected1)

      val expected2 = new StockQuote("PILG", "725.96", "721.32")
      when( mockRetriever.getStockQuote( expected2.symbol )).thenReturn(expected2)

      val app = new StockQuoteApp( mockRetriever, repo )

      app.findAndUpdateStockQuote(expected1.symbol)
      repo.get( expected1.symbol).get should be === expected1 

      app.findAndUpdateStockQuote(expected2.symbol)
      repo.get( expected2.symbol).get === expected2 

      repo.isEmpty() should be === false 
      repo.size() should be === 2

      val expected3 = new StockQuote("APPL", "101.50", "101.46")
      when( mockRetriever.getStockQuote( expected3.symbol )).thenReturn(expected3)

      app.findAndUpdateStockQuote(expected3.symbol)
      repo.get( expected3.symbol).get should be === expected3 

      repo.isEmpty() should be === false 
      repo.size() should be === 2

      verify(mockRetriever, times(2) ).getStockQuote(expected1.symbol)
      verify(mockRetriever, times(1) ).getStockQuote(expected2.symbol)
    }
  }

}

Oh yes, I forgot to mention that ScalaTest has a special method called ===. In Scala, identifiers can be mixed characters, and the triple equals serves as an assertion equality operator to compare expected and actual results. This operator aid debugging and when a test fails prints out the expected and actual values and more important where in the stacktrace the failure occured. In my opinion, for the negative cases, ScalaTest needs an associative operator !===.

In the unit test, please note, I have duplicated some assertions with the should matchers and also the equality operator in ordered to prove that the two forms are the same. For mathematical derived testing for finance or science, I think that I would prefer the “===” operator rather the long english form. It will depend on your style of testing, but the fact that ScalaTest allows different art forms, in itself, is great.

      repo.isEmpty() should be === false 

      repo.isEmpty() should be !=== true // Does not exist in ScalaTest 1.3

      assert ( repo.size() === false )

ScalaTest has good documentation on all of the available types of ShouldMatchers here. You will find relational operations like greaterThan or lessThan over there.

Here follows the second unit test that verifies the operation of the quote key value repository.

package uk.co.xenonique.stockquoteapp_scala

import org.scalatest.WordSpec
import org.scalatest.matchers.ShouldMatchers
import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner

@RunWith(classOf[JUnitRunner])
class QuoteRepositoryKeyValueTest extends WordSpec with ShouldMatchers {

  "quote repository key value store" should {
    "initialise well" in {
      val store:QuoteRepository = new QuoteRepositoryKeyValueStore()
      assert( store.isEmpty() === true )
      assert( store.size() === 0 )
      store.isEmpty should be === true
      store.size() should be === 0
    }
  }

  "quote repository key value store" should {
    "store and retrieve stock quotes" in {
      val store = new QuoteRepositoryKeyValueStore()
      val expected1 = new StockQuote("PILGRIM", "123.45", "123.12" )

      store.store(new StockQuote(expected1))
      assert( store.isEmpty() === false )
      assert( store.size() === 1 )
      store.isEmpty should be === false
      store.size() should be === 1

      assert( store.get("PILGRIM").get === expected1 )

      val expected2 = new StockQuote("PILGRIM", "555.55", "555.12" )
      store.store(expected2)
      assert( store.isEmpty() === false )
      assert( store.size() === 1 )

      store.get("PILGRIM").get should not be expected1
      store.get("PILGRIM").get should be === expected2
      assert( store.get("PILGRIM").get === expected2 )
    }
  }

  "quote repository key value store" should {
    "store and retrieve multiple stock quotes" in {
      val store = new QuoteRepositoryKeyValueStore()
      assert( store.isEmpty() === true )
      assert( store.size() === 0 )

      val quotes = List(
        new StockQuote( "LYG", "4.020", "4.015" ),
        new StockQuote( "RBS.L", "39.58", "39.48" ),
        new StockQuote( "HSBC.L", "646.65", "646.62" ),
        new StockQuote( "ORCL", "27.75", "27.74" ) )

      for (quote <- quotes) store.store(quote)

      assert( store.size() === quotes.length )
      assert( store.isEmpty() === false)

      for (quote <- quotes) {
        assert( store.contains(quote.symbol ) === true )
        assert( store.get(quote.symbol ).get == quote )
      }

      val symbols = store.getSymbols()
      assert( symbols.size === quotes.size )
      for ( quote <- quotes) {
        assert( symbols.contains(quote.symbol ) === true )
      }

      store.clear()
      assert( store.isEmpty() === true )
      assert( store.size() === 0 )
    }
  }
}

In part 3, we will see the code implementation of quote retriever in Scala.

Learn a new language! Maintenance mode programmers please go elsewhere!

Word.

2 Comments

  1. Hi Peter,

    There is a slight mistake in your first example. It is an example of a Specification written with the *specs* project: http://code.google.com/p/specs and not ScalaTest. It can be rewritten more concisely as:

    import org.specs._

    class MySpec extends SpecificationWithJUnit {… }

    Note also that the specs library has been superceded by specs2: http://specs2.org, offering the same kind of features and more.

    That being said, your post is a fine example on how to use ScalaTest to write BDD specifications with Scala!

    Eric.

    Comment by Eric — 25 July 2011 @ 5:03 am

  2. Thank you Eric. I updated the blog entry.

    Comment by admin — 25 July 2011 @ 5:53 am

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

Hey all! Thanks for visiting. I provide fringe benefits to interested readers: checkout consultancy, training or mentorship Please make enquiries by email or
call +44 (0)7397 067 658.

Due to the Off-Payroll Working plan for the UK government, I am enforcing stricter measures on contracts. All potential public sector GOV.UK contracts engagements must be approved by QDOS and/or SJD Accounting. Please enquire for further information.