Unit tests

Daestrum

Expert
Licensed User
Longtime User
With B4R with suitable unit tests you can catch when an external library has changed (like it returns an extra value or different type)
The test will point to where in your code you need to allow for the change and what caused it.

Like GitHub etc, they have unit tests because of multiple people editing files, run the 'unit tests' to see if they changed how a module works and how it breaks your code.
 

EnriqueGonzalez

Expert
Licensed User
Longtime User
Tests protect you from your future self.

say you have the following function:

B4X:
private Sub operation(a As Int, b As Int, c As String) As Int
    Select c
        Case "disguisse"
            Return (a + b) * 3 / 2
        Case "encrypt"
            Return (a * b * 2) + 5
    End Select
End Sub

and i use it like this:
operation(5,3,"disguissse")

i will always expect a 12 to be returned.

But in the future, like a couple of months later, a new feature is implemented that changes the function, say you or a coworker
B4X:
private Sub operation(a As Int, b As Int, c As String) As Int
    Select c
        Case "disguisse"
            Return a + b * 3 / 2
        Case "encrypt"
            Return (a * b * 2) + 5
    End Select
End Sub
as you can see parentheses has been removed. and now the same function returns 9

if i was careful enough to create a test, say something as simple as:
B4X:
    assert(operation(5, 3, "disguisse"), 12)
private Sub assert(fun As Int, expected As Int) As Boolean
    If fun <> expected Then
        Log($"function returned ${fun} but was expected to return ${expected}"$)
    End If
    Return fun = expected
End Sub
the moment i run my unit tests, this particular test will fail. so the solution becomes.
B4X:
private Sub operation(a As Int, b As Int, c As String) As Int
    Select c
        Case "disguisse"
            Return (a + b) * 3 / 2
        Case "disguisse_2"
            Return a + b * 3 / 2
        Case "encrypt"
            Return (a * b * 2) + 5
    End Select
End Sub

and thats the sole pourpose of tests, take into consideration, that people write code for years on a single project and small projects become large codebases, if you don't prepare for that, you won't scale.
 

Sandman

Expert
Licensed User
Longtime User
A user tried to make their own solution, but it never got any traction. It also couldn't be cross-platform, so that's also a lacking thing.

I've also been interested in unit tests for a long time, but there has never been much interest by the forum members (and thus no interest from Erel). It would be very nice if this thread could perhaps change that, so please continue talking about it. :)

(I tried making a custom cross-platform solution myself, but I gave up on that - I felt it was too difficult for me. I suspect it's a lot more fitting to have it built-in into B4X itself.)
 

EnriqueGonzalez

Expert
Licensed User
Longtime User
I suspect it's a lot more fitting to have it built-in into B4X itself.
beside of some metaprogramming, i believe that we only need Javaobject (may be reflection too) to create such framework. as can we create something like this:

test it it will work.
B4X:
public Sub repl
    Log(assert("operation", Array As Object(5, 3, "disguisse"), 12))
End Sub

private Sub assert(function As String, values() As Object, expected As Object) As Boolean
    Dim result As Object = call_sub_dynamic(function, values)
    If Not(result = expected) Then
        Log($"${function} returned ${result} but was expected to return ${expected}"$)
    End If
    Return result = expected
End Sub

private Sub operation(a As Int, b As Int, c As String) As Int
    Select c
        Case "disguisse"
            Return (a + b) * 3 / 2
        Case "disguisse_2"
            Return a + b * 3 / 2
        Case "encrypt"
            Return (a * b * 2) + 5
    End Select
End Sub

private Sub call_sub_dynamic(name As String, arr() As Object) As Object
    Dim jo As JavaObject = Me
    Return jo.RunMethod($"_${name}"$, arr)
End Sub
 

tchart

Well-Known Member
Licensed User
Longtime User
I dont think its necessary to use Java Object, a really simple option is something like this.

B4X:
Sub AppStart (Args() As String)
    #if UNIT_TESTS
        RunTests
    #End If 
    Log("Hello world!!!")
End Sub

Sub OnePlusTwo As Int
    Return 1+2
End Sub

#if UNIT_TESTS
Sub RunTests    
    Assert(OnePlusTwo,3)
    Assert(OnePlusTwo,1)
End Sub

Sub Assert(A As Object, B As Object)
    Return IIf(A=B,Pass,Fail)
End Sub

Sub Pass
    Log("Pass") 'Or write to a file
End Sub

Sub Fail
    Log("Fail") 'Or write to a file
End Sub    
#End If
 
Last edited:

tchart

Well-Known Member
Licensed User
Longtime User
I think Main is probabaly the best place to have the tests because even if you have an empty code module there will be traces of the module in the Jar file - this is generally why repos have two projects instead of build configurations...

1736883591022.png
 

Sandman

Expert
Licensed User
Longtime User
i believe that we only need Javaobject
That would make it non-cross-platform.

a really simple option is something like this
I've never seen unit tests interwoven with the actual code like that. Seems messy to me.

I think Main is probabaly the best place to have the tests because even if you have an empty code module there will be traces of the module in the Jar file - this is generally why repos have two projects instead of build configurations...
Well, if it was integrated into B4X, you could have a special type of module just for tests, that never gets included into a final build. (I'm obviously hand-waving a bit here, but I hope the idea comes through.)
 

tchart

Well-Known Member
Licensed User
Longtime User
I've never seen unit tests interwoven with the actual code like that. Seems messy to me.


Well, if it was integrated into B4X, you could have a special type of module just for tests, that never gets included into a final build. (I'm obviously hand-waving a bit here, but I hope the idea comes through.)
Agree. It is messy but the tests wouldnt appear in Release builds...

Special type of module is the way to go I think or like I mentioned a separte sub but you would end up with an empty class in the Jar.
 

hatzisn

Expert
Licensed User
Longtime User
From my understanding, some programming languages use a function call assert to test the functions.
Not sure this practice is useful in RAD tool like B4X or it can be a topic for debate.
Maybe we can test the inputs like division by zero, input Double value where Integer is expected or input String value to an input that expects numeric and input a very long String to test the limit in database field.

My thought exactly. Maybe a new test class that checks inputs and result compared to anticipated result. Possibly the test calling method will be in a '#IF DEBUG' clause.
 

hatzisn

Expert
Licensed User
Longtime User
I dont think its necessary to use Java Object, a really simple option is something like this.

B4X:
Sub AppStart (Args() As String)
    #if UNIT_TESTS
        RunTests
    #End If
    Log("Hello world!!!")
End Sub

Sub OnePlusTwo As Int
    Return 1+2
End Sub

#if UNIT_TESTS
Sub RunTests 
    Assert(OnePlusTwo,3)
    Assert(OnePlusTwo,1)
End Sub

Sub Assert(A As Object, B As Object)
    Return IIf(A=B,Pass,Fail)
End Sub

Sub Pass
    Log("Pass") 'Or write to a file
End Sub

Sub Fail
    Log("Fail") 'Or write to a file
End Sub 
#End If

Great example. My concern is that if we declare something as an object will there be equality in A=B? Then again it is almost 1:30 in the early morning and it might be possible that my mind is playing tricks on me at this hour.
 
Last edited:

hatzisn

Expert
Licensed User
Longtime User
HI, All

I know about this term only theoretically.
How should it look in B4X development ? Especially in B4R ...
Any example of codes ?

I did not know it even theoritically but only intuitively when checking my code.
 
Top