My Scala 3 SimpleTest source code (mini testing framework)

In the process of writing the Scala Cookbook for Scala 3, there were days when it was hard to find a working testing framework. As a result, I decided to write my own Scala 3 testing framework. Calling it a framework is a bit of a joke, as it’s only about 88 lines of source code. I named that library SimpleTest, and you can find it at github.com/alvinj/SimpleTest.

So I can easily find the source code later, I’m putting Version 0.3 of the source code here:

package com.alvinalexander.simpletest

/**
 * All of the source code in this file is distributed under the
 * GNU General Public License v3.0. See the LICENSE file in this
 * project, or https://choosealicense.com/licenses/gpl-3.0 for
 * more details.
 *
 * Created by Alvin J. Alexander, https://alvinalexander.com
 */
package support {
    val AnsiRed   = "\u001B[31m"
    val AnsiGreen = "\u001B[32m"
    val AnsiYellow = "\u001B[33m"
    val AnsiReset = "\u001B[0m"
    def printRed(s: String)    = println(s"${AnsiRed}${s}${AnsiReset}")
    def printGreen(s: String)  = println(s"${AnsiGreen}${s}${AnsiReset}")
    def printYellow(s: String) = println(s"${AnsiYellow}${s}${AnsiReset}")
}

import support._

object SimpleTest:

    private def _True(
        blockOfTestCode: => Boolean,
        trueString: String,
        falseString: String
    ): Unit =
        if blockOfTestCode then
            printGreen(trueString)
        else
            printRed(falseString)
        end if

    /**
     * Assert that an expression is true.
     * @param blockOfTestCode The expression to test.
     * @param num The test number.
     */
    def True(blockOfTestCode: => Boolean, num: Int): Unit =
        _True(
            blockOfTestCode,
            s"(true)  test $num",
            s"(false) test $num"
        )

    /**
     * Assert that an expression is true.
     * @param blockOfTestCode The expression to test.
     * @param desc The test description.
     */
    def True(blockOfTestCode: => Boolean, desc: String): Unit =
        _True(
            blockOfTestCode,
            s"(true)  $desc",
            s"(false) $desc"
        )

    private def _False(
        blockOfTestCode: => Boolean,
        trueString: String,
        falseString: String
    ): Unit =
        if blockOfTestCode == false then
            printGreen(trueString)
        else
            printRed(falseString)
        end if

    /**
     * Assert that an expression is false.
     * @param blockOfTestCode The expression to test.
     * @param num The test number.
     */
    def False(blockOfTestCode: => Boolean, num: Int): Unit =
        _False(
            blockOfTestCode,
            s"(true)  test $num",
            s"(false) test $num"
        )

    /**
     * Assert that an expression is false.
     * @param blockOfTestCode The expression to test.
     * @param desc The test description.
     */
    def False(blockOfTestCode: => Boolean, desc: String): Unit =
        _False(
            blockOfTestCode,
            s"(true)  $desc",
            s"(false) $desc"
        )

    /**
     * Assert that the two given values are equal (`==`).
     * @param expected The expected result.
     * @param actual The actual result.
     * @param desc A description of the test.
     */
    def Equals(expected: Any, actual: Any, desc: String): Unit =
        if expected == actual then
            printGreen(s"(true) $desc")
        else
            printRed(s"(false) EXPECTED: ($expected), ACTUAL: ($actual), DESC: $desc")
        end if

    def Todo(desc: String): Unit =
        printYellow(s"TODO:   $desc")

    /**
     * This is a different approach so you don’t have to supply
     * a description. Just let this object keep track of the
     * test numbers for you.
     */
    private var testCount = 0
    def True(blockOfTestCode: => Boolean): Unit =
        testCount += 1
        if blockOfTestCode then
            printGreen(s"(true)  test $testCount")
        else
            printRed(s"(false) test $testCount")
        end if
    def False(blockOfTestCode: => Boolean): Unit =
        testCount += 1
        if blockOfTestCode == false then
            printGreen(s"(true)  test $testCount")
        else
            printRed(s"(false) test $testCount")
        end if

    /**
     * Assert that the two given values are equal (`==`).
     * @param expected The expected result.
     * @param actual The actual result.
     */
    def Equals(expected: Any, actual: Any): Unit =
        //TODO decide on what output you want to see here
        testCount += 1
        if expected == actual then
            printGreen(s"(true) EXPECTED: ($expected), ACTUAL: ($actual)")
        else
            printRed(s"(false) EXPECTED: ($expected), ACTUAL: ($actual)")
        end if

end SimpleTest

That code can use some refactoring, but (a) it did what I needed it to, and (b) writing the Scala Cookbook was the highest priority at the time I wrote this code. I know my OKRs. ;)

Demonstration code

Also for myself, this code shows how to use that library in Scala 3:

package tests

import com.alvinalexander.simpletest.SimpleTest._

@main def tests =

    // run tests and give them descriptions
    True(1 == 1,  "1 == 1 (expecting green)")
    True(1 == 2,  "1 == 2 (expecting red)")
    False(1 == 2, "1 == 2 (expecting green)")
    False(1 == 1, "1 == 1 (expecting red)")
    Equals(1, 1,  "i expect green")
    Equals(1, 2,  "i expect red here")
    Todo("don’t forget to test 2 == 3")
    
    // run tests but only give them numbers
    True(1 == 1,   1)
    True(2 == 2,   2)
    True(3 == 3,   3)
    False(1 == 7,  4)
    False(1 == 8,  5)
    False(6 == 60, 6)

    // numbering is too much work, just let the object
    // keep track of the test numbers
    True(1 == 1)
    False(1 == 2)
    Equals(1, 1)

package t1 {
import com.alvinalexander.simpletest.SimpleTest._

    @main def tests =

        // use `True` to assert that an expression is true
        True(1 == 1,  "1 == 1 (expecting green)")
        True(1 == 2,  "1 == 2 (expecting red)")

        // use `False` to assert that an expression is false
        False(1 == 2, "1 == 2 (expecting green)")
        False(1 == 1, "1 == 1 (expecting red)")

        // use `Equals` to assert that two objects are `==`
        Equals(1, 1,  "i expect green")
        Equals(1, 2,  "i expect red here")

        // in case you want to note tests that you intend to run
        Todo("don’t forget to test 2 == 3")

        // just run some tests and simpletest will keep track of
        // the test numbers for you
        True(1 == 1)
        False(1 == 2)
        Equals(1, 1)

}

If you need a real testing framework for Scala 3, I recommend something like ScalaTest or mUnit, but for the purposes of the Scala Cookbook I needed something that worked every day, so I wrote this.