Question
· May 13, 2023

Debugging Unittests in InterSystems IRIS

Hi folks!

Those who actively use unittests with ObjectScript know that they are methods of instance but not classmethods.

Sometimes this is not very convenient. What I do now if I face that some test method fails I COPY(!) this method somewhere else as classmethod and run/debug it.

Is there a handy way to call the particular unittest method in terminal?  And what is more important, a handy way to debug the test method?

Why do we have unittest methods as instance methods? 

Discussion (25)4
Log in or sign up to continue

A handy way to call UnitTest Case method in a terminal

Do ##class(%UnitTest.Manager).DebugRunTestCase("", "[ClassName]", "", "[MethodName]")

Run all Test methods for a TestCase:

Do ##class(%UnitTest.Manager).DebugRunTestCase("", "[ClassName]", "", "")

Placing a "break" line within a method can be useful when iterating creating the test. See the variables. Run other code and then type "g"+ [Enter] to continue.

The instance gives context to current test run, when raising assertions and other functionality.

I am utilizing properties on class methods to good effect.

I would not use a classmethod only approach for normal development.

There is nothing stopping a community parallel UnitTest.Manager re-implementation that follows a ClassMethod pattern.

Some have reimplemented UnitTest.Manager:

1) Without Deleteing the test classes at end of run (With Run instead of DebugRun)

2) Not needed ^UnitTestRoot to be defined.

@Evgeny Shvarov I have a detailed writeup here (although Dmitry already hit the important point re: IPM): https://community.intersystems.com/post/unit-tests-and-test-coverage-obj...

A few other notes:

Unit test class instances have a property (..Manager) that refers to the %UnitTest.Manager instance, and may be helpful for referencing the folder from which unit tests were loaded (e.g., to load additional supporting data or do file comparisons without assuming an absolute path) or "user parameters" / "user fields" that were passed in the call to run tests (e.g., to support running a subset of tests defined in unit test code). Sure, you could do the same thing with PPGs or % variables, but using OO features is much better.

I'll also often write unit tests that do setup in OnBeforeAllTests and cleanup in %OnClose, so that even if something goes very horribly wrong it'll have the best chance of actually running. Properties of the unit test are useful to store state relevant to this setup - the initial $TLevel (although that should always be 0), device settings, global configuration flags, etc.

@Evgeny Shvarov my hacky way of doing this is to create an untracked mac file with ROUTINE debug defined.

I just swap in the suite or method I want to run per Alex's instructions, set my breakpoints in VS code and make sure the debug configuration is in my VSCode settings:

    "launch": {

        "version": "0.2.0",

        "configurations": [

            {

                "type": "objectscript",

                "request": "launch",

                "name": "debugRoutine",

                "program": "^debug"

            }

        ]

    }

Why are unit test methods instance methods? Since a running unit test is an instantiated object (%RegisteredObject), the unit test class itself can have custom properties, and the instance methods can use those properties as a way to share information. For example, initialize the properties in %OnBeforeAllTests(), and then access/change the properties in the test methods. 

Thanks @Joel Solon!

But all this could be achieved without instance methods, right? Anyway, I'm struggling to find an easy way to debug a failed unittest. @Michael Davidovich suggested the closest way to achieve it but I still want to find something really handy, e.g. an additional "clickable button" in VSCode above the test method that invites "debug this test method". Similar what we have for class methods now - debug this classmethod and copy invocation.

That'd be ideal.
 

Anything can be achieved without instance methods. The point here is that instance methods exist in object-oriented systems because they are considered a good, straightforward way to achieve certain things. In the case of unit tests sharing information using properties, that approach saves you from having to pass info around as method arguments, or declaring a list of public variables.