Skip to content

KirkBrooks/yaUT

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

51 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

version platform license downloads

yaUT - yet another Unit Test

Light-weight unit testing for 4D.

The class can be used to create and evaluate a test in a single line or can be pushed onto a collection for further examination. The syntax is inspired by JEST.

Testing in 4D

Unit tests have been challenging to write in 4D. Testing is flossing or eating broccoli - everyone agrees it’s good for you, most folks say they do it more than they actually do and everyone feels better after having done it. The key to accomplishing these sort of tasks is making them easy to do - that’s what this class does.

There’s no UI required and you have two options for presenting results:

  • append result description to a text variable and present in an ALERT or other form
  • accumulate results in a collection and present in a form

Being able to display results in an ALERT makes it very easy and fast to setup unit test methods without a lot of overhead. On the other hand there is a lot of information available if you capture each one in a collection.

It’s nice to have choices.

A big benefit of yaUT is the ability to run project methods with or without parameters. This is a big benefit working with old projects where you may want to evaluate the responses of existing code. The thing about unit testing is the basic form of the tests is pretty much the same across language but the specifics of how you run that test tend to be specific to the language. JEST, for example, has a number of features specific to JSON. JEST is also a mature, rich testing framework. I encourage you to extend this repo, fork it and improve it.

Install

Simply add two classes to a project: UnitTest and _ObjectProto.

Tests

There are three steps required to set up a test:

  1. Instantiate the class with the description of what the test does
  2. Enter the expected result of the test
  3. Choose a ‘matcher’ function to evaluate an input and set the result

They must be done in order.

// instantiate the class and enter the description
$test:=cs.UnitTest.new("1 is equal to 1")
// set the expected value
$test.expect(1)
// chose a 'matcher' to evaluate and compare to the expected value
$test.toBe(1)
// and check the result
$pass:=$test.pass  //  $pass = True
ALERT($test.displayline)

This can be condensed by chaining the class functions. The above code is equivalent to:

$test:=cs.UnitTest.new("1 is equal to 1").expect(1).toBe(1)
$pass:=$test.pass  //  $pass = True
ALERT($test.displayline)

Make a class for each test and evaluate it once.

The .displayLine property is an easy way to see the results of the test.

  • ✅ 1 is equal to 1 (0 ms)
  • ❌ 1 is equal to 2 (0 ms)
  • ⚠️ 1 is not equal to 2: Incompatible data type - only scalar values and formulas supported.

These are the three types of display you may see. Each is a text string and may be displayed in an alert.

Generally you will be creating a lot of tests to be run at one time. A nice way to handle creating a lot of classes is with a constructor variable:

$test:=cs.UnitTest  //  make the constructor
$class:=$test.new("my new class instance")

Combined with chaining I can describe a test and capture the result all in one line. Try it:

$test:=cs.UnitTest  //  make the constructor

$result:="My Unit Test\n"  // a text variable to hold the results

$result+=$test.new("1 is equal to 1").expect(1).toEqual(1).displayline+"\n"
$result+=$test.new("1 is not equal to 5").expect(1).not().toEqual(5).displayline+"\n"
$result+=$test.new("1 is not null").expect(1).not().toBeNull().displayline+"\n"
$str:="This is a line of text"
$result+=$test.new("$str contains 'line of text'").expect($str).toMatch("line of text").displayline+"\n"

ALERT($result)

If you wanted to have the results of each test for deeper analysis you could push them onto a collection instead:

$test:=cs.UnitTest  //  make the constructor

$result:=New collection()

$result.push($test.new("1 is equal to 1").expect(1).toEqual(1))
$result.push($test.new("1 is not equal to 5").expect(1).not().toEqual(5))
$result.push($test.new("1 is not null").expect(1).not().toBeNull())
$str:="This is a line of text"
$result.push($test.new("$str contains 'line of text'").expect($str).toMatch("line of text"))

Using Formulas for test values

Some matcher functions can take a 4D https://developer.4d.com/docs/API/FunctionClass/ “Formula” as an input. There are several benefits this provides. Chief among them is the ability to call Project methods and evaluate the results.

Properties and Functions

Property Return Type Descripton
pass Boolean True when the test passes
isErr Boolean True if there is an error
error Text
description Text
matcher Text name of matcher function. If not() is used it appears in the text.
displayline Text Returns a text suitable for display in a listbox or text field based on the state of the object.
Ex: ✅ get_item() should be null (0 ms)
Function Name Parameters Return Type Description
Constructor $description: Text cs.UnitTest Initializes the object and sets the description.
expect $valueIn: Variant cs.UnitTest The expected value or a Formula that evaluates to the expected value.
Matchers
toEqual $input: Variant cs.UnitTest Checks if input is equal to an expected value.
Input may be a Formula that evaluates to the expected value.
Otherwise it is a scalar value and must be the same data kind as expected value.
toBe $input:Variant cs.UnitTest Checks if an input is the same as the expected value depending on its type.
Input may be a Formula that evaluates to the expected value.
If dealing with an object or collection checks to see if this is they are the same reference - that is, the same object and not simply the same values. Use .toEqual() or .toContain() to check values.
toMatch $pattern: Text cs.UnitTest Checks if a regular expression pattern matches the expected value.
Expected value must be text.
toContain $input cs.UnitTest If the expected value is an object or entity checks to see if it contains all the values in the input object.
Input may be a Formula that evaluates to an object or entity.
toBeNull None cs.UnitTest Checks if the expected value is null.
not None cs.UnitTest Reverses the reslut of the matcher. Basically syntatic sugar.
Other Functions
getExpectedValue None Variant Returns the expected value
getExpectedValueStr None Text Stringified expected value
getTestValue None Variant Returns the test value
getTestValueStr None Text Stringified test value