Customizing ABLUnit so that the Consultingwerk AssertException is handled as "Failure"

In Unit Testing (unhandled) runtime errors and errors thrown from assertion methods to validate a test’s result typically have a different meaning – although they are technically speaking both errors that are thrown from the test (or the tested code) to the test runtime.

ABLUnit distinguishes between failures and errors. Failures are caused by errors thrown from the assertion methods and errors are remaining unhandled runtime exceptions. By default, ABLUnit does only consider errors thrown by the ABLUnit assertion methods a failure. Errors thrown by the Consultingwerk Assertion methods are seen as errors.

ABLUnit distinguishes this by the type of errors catched by the test runtime: Errors of type OpenEdge.Core.AssertionFailedError are handled as a failure and all other types of errors count into error.

The following simple unit test shows the difference in how ABLUnit visualizes errors thrown by the Consultingwerk assertion methods:

Sample Unit Test
BLOCK-LEVEL ON ERROR UNDO, THROW.

CLASS Test.SCL1274.TestClass:
 
    @Test.
    METHOD PUBLIC VOID TestOeAssertion ():
        OpenEdge.Core.Assert:Equals(1, 2) .
    END METHOD.

    @Test.
    METHOD PUBLIC VOID TestConsultingwerkAssertion ():
        Consultingwerk.Assertion.Assert:Equals(1, 2) .
    END METHOD.

END CLASS.

 

Using the Include Files in Consultingwerk/Studio/AblUnit/11_6_0 it’s possible modify the ABLUnit classes so that the Consultingwerk AssertException is handled in the same way as the ABLUnit AssertFailedError:

 

Implementing the customization to ABLUnit

Due to the rather poor design of ABLUnit we cannot avoid modifying ABLUnit’s source code provided by Progress Software to achieve handling the two assertion related exceptions/error classes in the same way. We need to add code to the

  • OpenEdge.ABLUnit.Reflection.ClassAnnotationInfo
  • OpenEdge.ABLUnit.Reflection.ProcedureAnnotationInfo

classes.  In the ClassAnnotationInfo there are in total three CATCH blocks affected and in ProcedureAnnotationInfo there is a single CATCH block. We have implemented the customization by inserting the two include files near the locations where the AssertionFailedError is handled:

  • Consultingwerk/Studio/AblUnit/11_6_0/handle-consultingwerk-exception.i
  • Consultingwerk/Studio/AblUnit/11_6_0/handle-consultingwerk-exception2.i

Attached to this document you’ll find the two modified classes based on OpenEdge 11.6 ADE source code. Based on our testing those classes work also with OpenEdge 11.6.1 and 11.6.2

When implementing this for a different version of ABLUnit, search the ABLUnit source code for “AssertFailedError” and add the first include file just before CATCH blocks for AssertFailedError and the second include file in CATCH blocks for Progress.Lang.Error just before the IF THEN ELSE block where the error’s type is inspected.

Sample location for the first customization include file in ClassAnnotationInfo
            /* Mike Fechner, Consultingwerk Ltd. 27.05.2016
               Handle Consultingwerk AssertException (and derived types
               like ABLUnit AssertFailedError */
            {Consultingwerk/Studio/AblUnit/11_6_0/handle-consultingwerk-exception.i}

            CATCH err AS AssertionFailedError :
                testResult:TestResult = TestTestResult:StatusFailed.
                testResult:ErrorMessage = err:GetMessage().
                testResult:TestName = testMethod:getTestName().
                testResult:Error = err.
            END CATCH.
Sample location for the second customization include file in ClassAnnotationInfo
        CATCH e AS Progress.Lang.Error :
            IF expectedException = "" THEN
            DO:

                /* Mike Fechner, Consultingwerk Ltd. 27.05.2016
                   Handle Consultingwerk AssertException (and derived types
                   like ABLUnit AssertFailedError */
                {Consultingwerk/Studio/AblUnit/11_6_0/handle-consultingwerk-exception2.i testResult testMethod}

                IF (e:GetClass():TypeName = "OpenEdge.Core.AssertionFailedError") THEN
                DO:
                    testResult:TestResult  = TestTestResult:StatusFailed.
                    testResult:TestName = testMethod:getTestName().
                    testResult:Error = e.
                    testResult:ErrorMessage = e:GetMessage(1).
                END.
                ELSE
                DO:
                   testResult:TestResult  = TestTestResult:StatusError.
                    testResult:TestName = testMethod:getTestName().
                    testResult:Error = e.
                END.
            END.
            ELSE IF (ClassAnnotationInfo:IsTypeOf(e, GetExpectedErrorType(expectedException))) THEN
            DO:
                testResult:TestResult = TestTestResult:StatusPassed.
                testResult:TestName = testMethod:getTestName().
            END.
            ELSE
            DO:
                testResult:TestResult = OpenEdge.ABLUnit.Results.TestTestResult:StatusFailed.
                testResult:TestName = testMethod:getTestName().
                testResult:ErrorMessage = "Expecting:" + expectedException + " but found:" + e:GetClass():TypeName.
                testResult:Error = e.
            END.
        END CATCH.

Using the customized version of ABLUnit

In order to use the customized version of these two ABLUnit classes, they must be placed in a subdirectory OpenEdge.ABLUnit.Reflection underneath a directory that is in the PROPATH before the ablunit.pl library:

Attached Files

  File Modified

File ClassAnnotationInfo.cls

May 27, 2016 by Mike Fechner

File ProcedureAnnotationInfo.cls

May 27, 2016 by Mike Fechner