So by now you should have a simple app, that takes in some command line arguments & that's about it. Before we get too much further, let's create some tests for our code.
In order to make this simple, let's create some small classes that respresent our domain model. We'll be using case classes for these. You can think of case classes as something akin to structs. The Scala compiler generates some of the methods of the class for you if you add the case
qualifier at the start of the class name. Let's go ahead and define our first class, for a product from our base prices list.
final case class BaseProduct(productType: String, options: Map[String, Seq[String]], basePrice: Int)
There's a fair bit going on here:
- We've created a base product class, that takes a bunch of parameters in its constructor. These are automagically assigned to member variables. The values are:
productType: String
- this is saying that the variableproductType
is aString
;options: Map[String, Seq[String]]
-options
is aMap
(associative array, hash, etc.), withString
keys & values that are a sequence ofString
s. This could represent for example the JSON"colour": ["white", "dark"]
;basePrice: Int
-basePrice
is an integer (we are using cents in the homework task).
- The
final
modifier is saying that we're not going to allow subclassing of this class (as we've not designed this class for extension). - The
case
modifier tell the compiler to generate some useful functions for us (toString
,equals
, etc.).
Let's use this class to write some tests. Note that the tests we are going to write will be quite simple, and that in reality because the functions we'll be testing are compiler generated, we'd not normally test them. However, they are simple enough to show the ways that we can test. We'll be using ScalaTest for the testing, there are alternatives, but this is quite simple.
Here's our first test:
final class BaseProductSpec extends FlatSpec with Matchers {
"A base product" should "contain a product type " in {
BaseProduct("hoodie", Map.empty, 0).productType shouldEqual "hoodie"
}
}
Let's unpack this a bit too.
- Again we've made our class
final
. - We've extended from a parent class called
FlatSpec
, and the also mixed in a trait calledMatchers
. These two will give us access to the functionality we need to run the test. - We've instantiated the class as follows:
BaseProduct(...)
, normally we'd usenew BaseProduct(...)
to do this, but because the compiler generated some things for us (as it's a case class), we can omit thenew
. If you want to dig deeper, this is because we had anapply
method generated for us, and there's magic syntactic compiler sugar that meansBaseProduct.apply(...)
is equivalent toBaseProduct
. You'll see this exploited a lot in Scala.
Now, let's run the test:
> test
[info] BaseProductSpec:
[info] A base product
[info] - should contain a product type
[info] Run completed in 316 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[success] Total time: 1 s, completed 10/08/2017 5:19:03 PM
Success!!!
For practice, go ahead & create tests for each of the other fields we've added to the class (options
& basePrice
).
Further reading:
You've been introduced to a few new concepts, now's probably a good time to read up on them.
- Case classes & objects;
Map.empty
;- The
apply
method.