Unit testing in scala using scalatest

Harshal Patel
7 min readMay 12, 2021

What is unit testing?

According to a blog from DZone,

Unit tests are used to test individual code components and ensure that code works the way it was intended to. Unit tests are written and executed by developers. Most of the time a testing framework like JUnit is used. Test cases are typically written at a method level and executed via automation.

At first it may seem a bit complicated but let’s get started with an analogy. Suppose that you are laptop manufacturer and got a new order to build a laptop with specific requirements for some components. For example, you have to use the display of Samsung, Battery of LG, Hard Drive of Toshiba, RAM of Crucial and so on. So, consider the following 2 approaches to build the laptop.

# Approach — 1

  • Go to the accessories store
  • Check the compatibility
  • Buy all the listed parts
  • Put all the pieces together and build the laptop

Alright, now that you have your laptop ready, just boot it up. But, what to do if it doesn’t boot up properly due to some fault in display (or RAM, or Hard disk, or may be faulty joint of wires, who knows at this point)? Open the whole laptop again, fix the component (based on doubt), build again, boot again and repeat until all the stars align. Huhh.. Tired, right? Now, let’s see the other approach.

# Approach — 2

  • Go to the accessories store
  • Check the compatibility
  • Buy all the listed parts
  • Test the parts individually and replace if anything is faulty
  • Put all the pieces together and build the laptop

Wait, a single step changed and now does is guarantee that the built laptop will boot up properly? Well, the answer is still “NO”. But, the advantage here is now we know that the problem is related to infrastructure only (may have a faulty joint of wires) as all the components are working fine and we are sure of it. I think you know where we are heading. Enough of analogy, let’s setup a simple project and perform the unit testing.

How to perform unit testing?

Pre-requisites

Basic knowledge of Scala and Java programming is required.

  • IntelliJ IDEA (community 2020 or later) with Scala Plugin installed
  • JDK8
  • Scala (2.11.12)

Once everything is setup, in this example we will use maven as dependency manager.

  • Open IntelliJ → File → New Project → Select maven from the left side panel → Select JDK 1.8 (or navigate and add JDK to IntelliJ)
Project start-up
Select proper configuration and create boilerplate maven project
  • Click Next → Rename project and choose destination folder and hit the Create Button.

Note: You must avoid the project locations for which their absolute path contains whitespaces or characters like “-”. This has serious impacts like maven build process not considering the test classes at all.

  • Once the project is created, rename the folders under src/main/java and src/test/java to scala and your project structure should be as follows:
Initial project structure
Initial project structure

Adding scala framework support

  • Press Ctrl + Alt + Shift + S to open project structure → Go to Global Libraries → Click “+” and add scala 2.11.12 SDK by locally browsing or downloading
Setup Scala SDK
  • Now, right click on the Root Folder (scalaUnitTesting) and select Add Framework Support → Select Scala and Select proper SDK version.

Creating a simple class object
Now, let’s create a simple class.

  • Navigate to src/main/scala folder, right click and select New → Package and create com.example.scalatest using the prompt.
  • Navigate to scalatest package, right click and select New → Scala Class and create HelloScala object using the prompt. Write the following code and press Ctrl + Shift + F10 to run the same. It should print the Hi! from HelloScala on the console.
  • Add the dependencies to pom.xml and it will look as follows:
pm.xml with dependencies
  • For sbt based projects you should add the following dependency:
  • Refresh the maven project by clicking reload on top right corner (or Right Click → maven → Reimport) in the pom.xml . After all the dependencies are imported we are now good to start our unit testing.
  • To mimic a scenario, create the sayHello method in the HelloScala Object and call it from the main method.
Sample class

hitting run(Ctrl + Shift + F10) will output as follows. But, this is not a clean way to test as it gets messy when code grows (i.e. more methods and classes are added).

Hi! from HelloScala
--- Testing sayHello inside the main ---
sayHello method executed.
hello

Creating a simple test
Now, to create a unit test for the HelloScala Object, put your cursor anywhere inside HelloScala code and press Alt + Insert. This will open a generate dialogue → click unit Test… to create Unit tests. Now, select the proper test library and the methods as shown below:

Simple test for sayHello
Adding Unit tests using IntelliJ UI

Now, you can see that the same folder structure is followed under the /src/test/scala as src/main/scala and the Scala class HelloScala is appended with Test (HelloScalaTest ). This is very important as naming convention is considered at the time of building the project.

Note: There are several test styles available in scalatest (like FunSuite, FlatSpec, FunSpec). We are using the Fun Suit style which is easy to code and understand to my opinion.

Now, simply write the following code in the HelloScalaTest.scala to unit test the sayHello() method. At this point you can remove the contents from the main method as the method is tested inside its separate unit test.

sayHello method Test

Note: Try not to write any unneccesaryprintln statements in the final test code, you may do it while developing. If there are any println messages, you may see those at the time of build.

Now, you can run the test (or the whole tests inside the Test class) by clicking the green play button beside the method (in IntelliJ) or simply hit Ctrl + Shift + F10. You will see in the panel below, whether all the test cases are passed successfully or not, and appropriate assertion failure errors if anything fails to assert the expected outcome.

The unit testing also allows to implement methods of TraitBeforeAndAfter which has abstract methods before() and after() to basically do some pre and post processing before and after running the tests respectively. For example in spark, we may need to create a spark session before running all the tests that requires spark variable (or constant) to access the underlying functionalities. Similarly, after() can be used for clean up purpose (i.e. terminating sessions, closing files, etc.)

Now, when we run maven clean install, it will automatically run the test cases and we can see the following on the console (depending on the testing style we choose):

Tests running before building JAR

Why unit testing?

According to the post from DZone, following are the advantages of writing unit tests.

  1. Makes the Process Agile
    When you add more and more features to a software, you sometimes need to change old design and code. However, changing already-tested code is both risky and costly. If we have unit tests in place, then we can proceed for refactoring confidently.
  2. Quality of Code
    Unit testing improves the quality of the code. It identifies every defect that may have come up before code is sent further for integration testing. Writing tests before actual coding makes you think harder about the problem. It exposes the edge cases and makes you write better code.
  3. Finds Software Bugs Early
    Specifically where we build and deploy the JARs in the production, the test cases run before building the JAR, so if any test case fails, the build process will be terminated with proper message allowing us to take a look at tests and code to rectify the problem.
  4. Facilitates Changes and Simplifies Integration
    Unit testing verifies the accuracy of the each unit. Afterward, the units are integrated into an application by testing parts of the application via unit testing. Later testing of the application during the integration process is easier due to the verification of the individual units.
  5. Provides Documentation
    Unit testing provides documentation of the system. Developers looking to learn what functionality is provided by a unit and how to use it can look at the unit tests to gain a basic understanding of the unit’s interface (API).
  6. Reduce Costs
    Of course, bugs detected earlier are easier to fix because bugs detected later are usually the result of many changes, and you don’t really know which one caused the bug.

See also

  • Refer to the scalaUnitTesting GitHub repo for implementation. Go through various commits to better understand the process.
  • Scalatest documentation.

— — — — — — — — — — — — — Thank you — — — — — — — — — — — — —

--

--