B4A Class A Unit Test solution (class CTestRunner)

Discussion in 'Additional libraries, classes and official updates' started by jgmdavies, Feb 9, 2018.

  1. jgmdavies

    jgmdavies Member Licensed User

    I seem to now have a working Unit Test solution for B4A for anybody interested.

    The test code and test runner are included in the project to be tested, but can be excluded from compilation using a conditional directive - I use '#if UNIT_TESTS', with 'UNIT_TESTS' defined when required in a Build Configuration (B4A menu option: Project | Build Configurations).

    You can define any number of test classes and methods like so:
    Code:
    ' Class: CTest1

    #if UNIT_TESTS

    Sub Class_Globals
       Private TR As CTestRunner
    End Sub

    Public Sub Initialize
       TR = Starter.TestRunner
    End Sub

    public Sub Test_1
       TR.AssertIsTrue(True)
       TR.AssertIsTrue(1 = 1)
    End Sub

    public Sub Test_2
       TR.AssertIsFalse(False)
       TR.AssertIsFalse(1 = 0)
    End Sub

    public Sub Test_3
       TR.AssertIntsAreEqual(2, 2)
    End Sub

    public Sub Test_4
       TR.AssertIntsDiffer(2, 3)
    End Sub

    #else

    Sub Class_Globals
    End Sub

    #End If
    The attached Test Runner (class CTestRunner) will discover all Classes with names beginning with a specified prefix, e.g. 'CTest', and run all Subs with names beginning with a specified prefix, e.g. 'Test_'.

    In Starter I Have:
    Code:
    Sub Process_Globals
    #if UNIT_TESTS
       Dim TestRunner As CTestRunner
    #end if
    End Sub
    In my 'Main' Activity I have:
    Code:
    Sub Process_Globals
       
    Private NativeMe As JavaObject
    End Sub

    Sub Activity_Create(FirstTime As Boolean)

       
    If FirstTime Then
           NativeMe.InitializeContext

    #if UNIT_TESTS
           Starter.TestRunner.Initialize(NativeMe)
    #end if
       
    End If
    and later, to run the unit tests, log a test report, and show an Html version of the results via a WebView:
    Code:
    #if UNIT_TESTS
       Starter.TestRunner.Verbosity = 1

       ' Test all Classes beginning with 'ctest' / all Subs beginning with 'test'.
       Starter.TestRunner.RunAll("ctest", "test")
       Log(Starter.TestRunner.GetTextReport)

       Starter.ShowHtmlText = Starter.TestRunner.GetHtmlReport
       StartActivity(ShowHtml)
    #End If
    and beneath the Basic subs:
    Code:
    #if JAVA
       public String GetPackageCodePath()
       {
           return getPackageCodePath();
       }

       public Object GetProcessBA()
       {
           return processBA;
       }
    #End If
    Note that one Java method in CTestRunner ('GetClassNamesInPackage') uses a deprecated approach, and that also the whole approach may break with any new version of B4A (!).

    IMPORTANT - CTestRunner as attached only works with the Rapid Debugger. To use it with the Legacy Debugger, set the constant 'LEGACY_DEBUGGER' on line 357 to 'true'. I'll true to make this automatic soon.

    Hope this helps someone,
    Jim
     

    Attached Files:

  2. Sandman

    Sandman Active Member Licensed User

    I haven't had a chance to try this yet, but still have a question: Would it be possible to make an B4i version also?

    Also, I'd love to hear if anyone has tried this and have anything to share about the experience?
     
    walterf25 likes this.
  3. jgmdavies

    jgmdavies Member Licensed User

    Hi @Sandman - Part of the inline Java code in CTestRunner is definitely Android-specific and would requiring porting to iOS. Unfortunately we're non-Apple here (!) - hopefully someone else will comment.

    Generally I'm sure the code could be improved, and ideally we would have a UI to control which tests are executed etc. But I thought it was worth making a start, as these days I find it difficult to develop much business and utility code without unit testing, and other people in these forums have said similar things.

    I have some minor improvements coming if anyone would like them.

    Jim
     
    Last edited: Feb 13, 2018
  4. Sandman

    Sandman Active Member Licensed User

    Hi @jgmdavies, absolutely, please post the improvements as you make them. I doubt I'll have a chance to look at it in the next two weeks, but I'm very interested in using unit tests. I'm making a business app for Android and iOS and it's somewhat nerve-racking to make changes to it.

    I was thinking, do you think it would make sense to implement unit testing directly into the IDE? (I realize Erel would have to do that, just curious about your thoughts.)
     
  5. jgmdavies

    jgmdavies Member Licensed User

    Hi @Sandman, I'll post an update soon. Yes, it would absolutely make sense to have unit testing integrated in the B4A IDE. For example, it would be useful to have a UI for selecting the tests to be run - at the moment I use the 'prefix filter' approach you can see in the CTestRunner 'RunAll' sub to narrow down the test classes to be run, but I typically edit the Main to do that.

    As you say, we'd need Erel to do it - but I wonder if he's considered allowing people to add their own extensions/add-ins/add-ons to the B4A IDE? That would be one way to implement it, and folk could write different add-ons and perhaps share them. Ideally an add-on for unit testing would need:
    • Ability to show the add-on's UI on the host PC.
    • An API to access (basic info about) the class definitions in the currently-loaded project.
    • Ability to run the current project.
    Maybe it could be B4A with pieces of B4J? (sorry Erel...)

    Jim
     
  6. jgmdavies

    jgmdavies Member Licensed User

    Attached is a demo B4A project containing an updated version of the CTestRunner class described above, together with a Unit Test UI that runs on the connected Android device and lets you run selected tests and see test status. The test status is stored and retrieved from a CSV file in 'File.DirDefaultExternal'. The project works in both Rapid Debug and Release mode, but Legacy Debug mode still has issues.

    The idea is that you add any number of test classes modelled on 'CTest_1' or 'CTest_2' in the demo project, each with any number of test subs. Follow a naming convention, for example my test classes all start with 'CTest_', and test methods with 'Test_'. Test classes can include 'Setup' and 'Teardown' subs (see class CTest_1) which if present are called before/after each Test method in the class is run.
    You can also have overall Setup and Teardown, i.e. a Setup sub which is called before any Tests are run, and a Teardown sub which is called after all Tests have been run - see class 'CTest'.

    The demo UI includes a report option (the ^P button), which creates an HTML report in folder 'File.DirDefaultExternal'.

    I'm using this quite a lot, and now tend to add a test class as soon as I add a new business class. Feedback welcomed!

    Jim
     

    Attached Files:

    Sandman likes this.
  7. jgmdavies

    jgmdavies Member Licensed User

    Screenshot of the Android UI attached (slightly different buttons - sorry).
     

    Attached Files:

  8. Sandman

    Sandman Active Member Licensed User

    Hi @jgmdavies, sorry for not trying out CTestRunner yet - it's on my list of todos. Still very interested! (Any updates?)

    I was just struck with an idea, and thought I'd ask what you thought of it. Considering it's probably not very likely we will get unit tests to be a native part of the IDE any time soon: Would it make sense to make a B4J project that CTestRunner connected to, where one could configure what tests to run, and see the reports?

    That would minimize the reporting code we'd need in the app, and it could even work in parallel with the ordinary IDE.
     
  9. Sandman

    Sandman Active Member Licensed User

    Another question. How are you actually using this? Strictly for business logic where one can easily input data and evaluate output? Or are you also using this for more platform related things? Like, for instance, having a sub setting up a notification channel and then have a unit test to evaluate if the channel was created correctly? Or a unit test to check if a gps fix is received within one minute?
     
  10. jgmdavies

    jgmdavies Member Licensed User

    Hi Sandman,
    I'm afraid I haven't used B4A for a while, as doing 'other things'. (Also I kept nodding off - perhaps poetry-related?)
    So no significant updates since the last. I found it very useful for business logic, for the usual reasons. I think it could be used for 'platform related' tests, although I guess I'd be wary of adding much time-sensitive test code.
    I can't say much about the B4J idea at the moment - how were you thinking of linking the Test Runner code?
    Best,
    Jim
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice