Is there a unit testing module available?

fightlessbirds

New member
Joined
Apr 15, 2022
Messages
3
Does anyone know of a unit test module for Cerberus? Web searches and forum searches have yielded nothing for me so far. If not I could see about rolling my own.

Edit:​

I ended up coding a simple module myself.
 
Last edited:

MikeHart

Administrator
Joined
Jun 19, 2017
Messages
3,281
Hi, welcome! No, not that I know of. Did you search on Github within Monkey X modules?
 

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
I don't know where I got this but on Github somewhere I can't remember the author. Maybe a member here or it might have been even older. I meant to try it but I have not yet. There was no example on how to use it but maybe it will come useful by just looking it through.

EDIT found the author I got it from, very long time ago

Code:
Strict

Import mojo

#Rem
Header: Simple unit testing framework
#End

Interface IUnitTest
   
    #Rem
    summary: Run test
    #End
    Method Run:Bool()

    #Rem
    summary: Get name of the test
    #End
    Method GetName:String()
   
End Interface

Class CompletedUnitTest
   
    Const SUCCESS:Int = 1
    Const FAILURE:Int = 2  

    Field test:IUnitTest
    Field status:Int
   
    Method New(test:IUnitTest, status:Int)
        Self.test = test
        Self.status = status
    End Method

End Class

Class UnitTestApp Extends App

    Method OnCreate:Int()
        Self.Setup()
        Self._countTests = Self._tests.Count()
       
        If (Self._countTests = 0) Then
            Error("No tests to run")
        End If
       
        SetUpdateRate(30)
        Return 0
    End Method
   
    Method OnUpdate:Int()
        If (Self._isCompleted) Return 0
   
        Self._currentTest = Self._tests.RemoveFirst()
       
        Local completedTest:CompletedUnitTest
       
        if (Self._currentTest.Run()) Then
            completedTest = New CompletedUnitTest(Self._currentTest, CompletedUnitTest.SUCCESS)
           
            #IF (TARGET <> "flash")
                Print(Self._currentTest.GetName()+" unit test... SUCCESS")
            #EndIf
        Else
            completedTest = New CompletedUnitTest(Self._currentTest, CompletedUnitTest.FAILURE)
           
            #IF (TARGET <> "flash")
                Print(Self._currentTest.GetName()+" unit test... FAILURE")
            #EndIf
            Self._countFailedTests+=1
        End If
       
        Self._completedTests.AddLast(completedTest)
       
        If (Self._tests.Count() = 0) Self._isCompleted = True
        Return 0  
    End
   
    Method OnRender:Int()
        Cls(0, 0, 0)
       
        Local offsetY:Int = 5
        Local scrollY:Int = Min(0.0, 12*(Ceil(DeviceHeight()/12) - (Self._completedTests.Count()+5)) + 8)
       
        For Local completed:CompletedUnitTest = EachIn Self._completedTests      
            If (completed.status = CompletedUnitTest.SUCCESS) Then
                SetColor(0,255,0)
                DrawText(completed.test.GetName()+" unit test... SUCCESS", 5, offsetY + scrollY)
            Else
                SetColor(255,0,0)
                DrawText(completed.test.GetName()+" unit test... FAILURE", 5, offsetY + scrollY)
            End If          
           
            offsetY+=12  
        Next

        If (Self._isCompleted) Then
            If (Self._countFailedTests > 0) Then
                SetColor(255,0,0)
            Else
                SetColor(0,255,0)      
            End If
           
            DrawText("---", 5, offsetY + scrollY)
           
            offsetY+=12  
            DrawText(Self.GetName()+" unit testing complete.", 5, offsetY + scrollY)
               
            offsetY+=12  
            DrawText("Total tests: "+Self._countTests+
                ", successful tests: "+(Self._countTests-Self._countFailedTests)+
                ", failed tests: "+Self._countFailedTests, 5, offsetY + scrollY)
               
            Error("")
        End If
       
        SetColor(255, 255, 255)
        Return 0  
    End Method
   
    #Rem
    summary: Add unit test for running
    #End
    Method AddTest:Void(test:IUnitTest)
        Self._tests.AddLast(test)  
    End Method
   
    #Rem
    summary: Setup application for unit testing
    #End  
    Method Setup:Void() Abstract
   
    #Rem
    summary: Get name of the tests collection
    #End
    Method GetName:String() Abstract
   
Private
   
    Field _countTests:Int
    Field _countFailedTests:Int
   
    Field _tests:List<IUnitTest> = New List<IUnitTest>
    Field _completedTests:List<CompletedUnitTest> = New List<CompletedUnitTest>
   
    Field _currentTest:IUnitTest
    Field _isCompleted:Bool = False
   
End Class

Class UnitTest
   
    #Rem
    summary: Asserts that a condition is true.
    #End  
    Function AssertTrue:Bool(value:Bool, message:String = "")
        If (Not value) Return UnitTest._AssertError("AssertTrue(): " + _ErrorFormat(message))
        Return True          
    End Function
   
    #Rem
    summary: Asserts that a condition is false.
    #End
    Function AssertFalse:Bool(value:Bool, message:String = "")  
        If (value) Return _AssertError("AssertFalse(): " + _ErrorFormat(message))
        Return True          
    End Function
   
    #Rem
    summary: Asserts that two objects are equal.
    #End
    Function AssertSame:Bool(expected:Object, actual:Object, message:String = "")      
        If (expected <> actual) Then
            Return _AssertError("AssertEquals(): " + _ErrorFormat(message))
        End If
        Return True      
    End Function
   
    #Rem
    summary: Asserts that two ints are equal.
    #End
      Function AssertEqualsI:Bool(expected:Int, actual:Int, message:String = "")
        If (expected <> actual) Then
            Return _AssertError("AssertEqualsI(): " + _ErrorFormatEqualI(expected, actual, message))
        End If
        Return True  
      End Function
   
    #Rem
    summary: Asserts that two floats are equal.
    #End
      Function AssertEqualsF:Bool(expected:Float, actual:Float, delta:Float = 0, message:String = "")
        If (Abs(expected - actual) > delta) Then
            Return _AssertError("AssertEqualsF(): " + _ErrorFormatEqualF(expected, actual, delta, message))
        End If
        Return True  
      End Function
   
    #Rem
    summary: Asserts that two strings are equal.
    #End
      Function AssertEqualsS:Bool(expected:String, actual:String, message:String = "")
        If (expected.Compare(actual) <> 0) Then
            Return _AssertError("AssertEqualsS(): " + _ErrorFormatEqualS(expected, actual, message))
        End If
        Return True  
      End Function
   
    #Rem
    summary: Asserts that an object isn't null.
    #End
    Function AssertNotNull:Bool(obj:Object, message:String = "")
        If (obj = Null) Then
            Return _AssertError("AssertNotNull(): " + _ErrorFormat(message))
        End If
        Return True  
    End Function

    #Rem
    summary: Asserts that an Object is null.
    #End
    Function AssertNull:Bool(obj:Object, message:String = "")
        If (obj <> Null) Then
            Return _AssertError("AssertNull(): " + _ErrorFormat(message))
        End If
        Return True  
    End Function
   
Private
    Const DEFAULT_MESSAGE:String = "failure"

    Function _ErrorFormat:String(message:String)
        Local formatted:String
        If message <> "" Then
            formatted = message + " "
        Else
            formatted = DEFAULT_MESSAGE + " "
        End If
        Return formatted
    End Function
   
    Function _ErrorFormatEqualI:String(expected:Int, actual:Int, message:String)
        Return _ErrorFormat(message) + "expected:<"+expected+"> but was:<"+actual+">"
    End Function
   
    Function _ErrorFormatEqualF:String(expected:Float, actual:Float, delta:Float, message:String)
        Return _ErrorFormat(message) + "expected:<"+expected+"> with delta:<"+delta+"> but was:<"+actual+">"
    End Function
   
    Function _ErrorFormatEqualS:String(expected:String, actual:String, message:String)
        Return _ErrorFormat(message) + "expected:<"+expected+"> but was:<"+actual+">"
    End Function
   
    Function _AssertError:Bool(message:String)
        #If (CONFIG = "debug")
            Print(message)
            Error(message)
        #End
       
        Return False
    End Function  

End Class
 
Last edited:

fightlessbirds

New member
Joined
Apr 15, 2022
Messages
3
Cool! I will check this out. Thank you Jimmy.

I've started working on my own unit test module, and I'll share it here when finished.
 

fightlessbirds

New member
Joined
Apr 15, 2022
Messages
3
Here's what I managed to throw together. :)

Module Source​

Cerberus:
Strict

Class UnitTestSuite

    Method AddTest:Void(test:UnitTest)
        If test = Null
            Error("UnitTestSuite.addTest(): test parameter is Null")
        End
       
        _tests.PushLast(test)
    End
 
    Method Run:Void()
        While _tests.Length > 0
            Local test := _tests.PopFirst()
            test.Run()
            If test.Passed
                _testsPassed += 1
            Else
                _testsFailed += 1
            End
            _completedTests.PushLast(test)
        End
     
        Print("================================~n        Unit Test Results~n================================")
        Local i := 1
        For Local test := EachIn _completedTests
            Print("~nTest #" + i + ": " + test.GetName())
            test.PrintReport()
            i += 1
        Next
        Print("~nTests passed: " + _testsPassed + "~nTests failed: " + _testsFailed)
    End

Private

    Field _tests := New Deque<UnitTest>()
    Field _completedTests := New Deque<UnitTest>()
 
    Field _testsPassed := 0
    Field _testsFailed := 0

End


Class UnitTest

    Method GetName:String() Abstract

    Method Run:Void() Abstract
 
    Method AssertEquals:Void(a:Int, b:Int, msg:String="")
        Local line:String
        If a = b
            line += "PASS AssertEquals "
        Else
            line += "FAIL AssertEquals "
            _passed = False
        End
        report.AddLast(line + msg)
    End
 
    Method AssertEquals:Void(a:Float, b:Float, msg:String="")
        Local line:String
        If a = b
            line += "PASS AssertEquals "
        Else
            line += "FAIL AssertEquals "
            _passed = False
        End
        report.AddLast(line + msg)
    End
 
    Method AssertEquals:Void(a:String, b:String, msg:String="")
        Local line:String
        If a = b
            line += "PASS AssertEquals "
        Else
            line += "FAIL AssertEquals "
            _passed = False
        End
        report.AddLast(line + msg)
    End
 
    Method AssertEquals:Void(a:Object, b:Object, msg:String="")
        Local line:String
        If a = b
            line += "PASS AssertEquals "
        Else
            line += "FAIL AssertEquals "
            _passed = False
        End
        report.AddLast(line + msg)
    End
 
    Method AssertTrue:Void(var:Bool, msg:String="")
        Local line:String
        If var
            line += "PASS AssertTrue "
        Else
            line += "FAIL AssertTrue "
            _passed = False
        End
        report.AddLast(line + msg)
    End
 
    Method AssertFalse:Void(var:Bool, msg:String="")
        Local line:String
        If Not var
            line += "PASS AssertFalse "
        Else
            line += "FAIL AssertFalse "
            _passed = False
        End
        report.AddLast(line + msg)
    End
 
    Method AssertNotNull:Void(obj:Object, msg:String="")
        Local line:String
        If obj
            line += "PASS AssertNotNull "
        Else
            line += "FAIL AssertNotNull "
            _passed = False
        End
        report.AddLast(line + msg)
    End
 
    Method AssertNull:Void(obj:Object, msg:String="")
        Local line:String
        If obj = Null
            line += "PASS AssertNull "
        Else
            line += "FAIL AssertNull "
            _passed = False
        End
        report.AddLast(line + msg)
    End
 
    Method PrintReport:Void()
        For Local line:String = EachIn report
            Print(line)
        Next
    End
 
    Method Passed:Bool() Property
        Return _passed
    End

Protected

    Field report:StringList = New StringList()
 
Private

    Field _passed:Bool = True

End

Example Source​

Cerberus:
Strict

Import unit

Class MyTestA Extends UnitTest

    Method GetName:String()
        Return "Integer test"
    End
 
    Method Run:Void()
        AssertEquals(1+1, 2, "One plus one is two")
        AssertEquals(1+1+1, 2, "One plus one is two")
    End

End

Class MyTestB Extends UnitTest

    Method GetName:String()
        Return "Null test"
    End
 
    Method Run:Void()
        AssertNull(Null, "Null is Null")
    End

End

Class MyTestC Extends UnitTest

    Method GetName:String()
        Return "Object test"
    End
 
    Method Run:Void()
        Local boxA:Object = BoxInt(10)
        Local boxB:Object = BoxInt(10)
        Local boxC:Object = boxB
 
        AssertEquals(boxA, boxB, "A = B")
        AssertEquals(boxB, boxC, "B = C")
    End

End

Function Main:Int()
    Local testSuite := New UnitTestSuite()
    testSuite.AddTest(New MyTestA())
    testSuite.AddTest(New MyTestB())
    testSuite.AddTest(New MyTestC())
    testSuite.Run()
 
    Return 0
End

Example Output​

Code:
================================
        Unit Test Results
================================

Test #1: Integer test
PASS AssertEquals One plus one is two
FAIL AssertEquals One plus one is two

Test #2: Null test
PASS AssertNull Null is Null

Test #3: Object test
FAIL AssertEquals A = B
PASS AssertEquals B = C

Tests passed: 1
Tests failed: 2
 
Last edited:
Top Bottom