ASUnit is a unit testing framework for
AppleScript originally written by Nir Soffer.
For a detailed description of the architecture of the original ASUnit framework,
read the file OldManual.md. Some advanced features of ASUnit (e.g., custom
TestCases and Visitors) are still described only in that document.
ASUnit's source code is thoroughly commented using HeaderDoc.
To get ASUnit, you may clone it from the GitHub repository:
git clone https://github.com/lifepillar/ASUnit.git
Alternatively, you may download a tarball containing the source code.
To build and install ASUnit, you have two options. If you have installed ASMake, you may just write:
cd ASUnit
./asmake install
Otherwise, you can install it manually with the following commands:
cd ASUnit
osacompile -o ASUnit.scptd -x ASUnit.applescript
mkdir -p ~/Library/'Script Libraries'/com.lifepillar
mv ASUnit.scptd ~/Library/Script\ Libraries/com.lifepillar
In either case, the file ASUnit.scptd will be installed in ~/Library/Script Libraries/com.lifepillar.
Note: If you get an error like the following:
The file “ASUnit.applescript” couldn’t be opened because
the text encoding of its contents can’t be determined. (-2700)
open the file with Script Editor, save it and try again.
To use ASUnit with AppleScript 2.3 or later (OS X 10.9 or later), add
property parent : script "com.lifepillar/ASUnit"
at the top of your test script. For previous systems, use:
property parent : ¬
load script (((path to library folder from user domain) as text) ¬
& "Script Libraries:com.lifepillar:ASUnit.scptd") as alias
Your test script must define a suite property and pass it to ASUnit's
autorun() handler:
property suite : makeTestSuite("A description for my tests")
autorun(suite)
You may run the test script inside AppleScript Editor,
from the command-line using osascript, or in other
environments (Script Debugger, AppleScriptObjC Explorer, …).
When you have several test files, you may run them all at once using
a test loader (there is no need to compile them in advance).
See Test Loader.applescript in the examples folder.
By default, if you run the tests in AppleScript Editor the output is written
to a new AppleScript Editor document; if you run the tests in the Terminal
the output is sent to stdout; otherwise, the output is sent to the current
application's console through log statements. You may, however, change this
by setting the suite's loggers property. The value of this property
must be a list of loggers (you may send the output to more than one
destination). Currently, ASUnit defines three loggers:
AppleScriptEditorLogger: sends colored output to an AS Editor window;StdoutLogger: sends colored output to stdout.ConsoleLogger: prints the output usinglogstatements (most portable logger).
Defining custom loggers should be fairly easy: you simply need to define a
script that inherits from TestLogger and override the print…() handlers to
generate the output you want. A more advanced alternative consists in
subclassing Visitor: see the section Creating new operations on a test suite
in OldManual.md for an example.
A test template is provided in the templates folder.
See the examples folder for complete examples.
The general structure of a test script is as follows:
script |One test set|
property parent : TestSet(me)
on setUp()
-- Code executed before each unit test
end
on tearDown()
-- Code executed after each unit test
end
script |a test|
property parent : UnitTest(me)
assert(1 + 1 = 2, "one plus one should be two")
assertEqual(2, 1 + 1)
refute(3 = 1 + 1, "1 + 1 should not be 3")
end script
script |another test|
property parent : UnitTest(me)
-- More assertions…
end
end script
script |Another test set|
property parent : TestSet(me)
-- More tests…
end
Each unit test is a script that inherits from UnitTest(me). Inside such scripts,
you may use a number of assertion handlers:
skip(msg): skips the current test.fail(msg): makes the test unconditionally fail.ok(expr): succeeds iff the booleanexprevaluates to true.notOk(expr): succeeds iffexprevaluates to false.assert(expr, msg)orshould(expr, msg): succeeds iffexpris true.refute(expr, msg)orshouldnt(expr, msg): succeeds iffexpris false.shouldRaise(num, object, msg): succeeds iffobjectraises exceptionnumwhen executed. Theobjectcan be a script object or a handler without parameters.shouldNotRaise(num, object, msg): succeeds iffobjectdoes not raise exceptionnumwhen executed. Theobjectcan be a script object or a handler without parameters.assertEqual(expr, value)orshouldEqual(expr, value): succeeds iffexpr=value.refuteEqual(expr, value)orshouldNotEqual(expr, value): succeeds iffexpr≠value.assertMissing(expr): a synonym forassertEqual(missing value, expr).assertObjCReference(expr): succeeds iffexpris a reference to a Cocoa object.refuteObjCReference(expr): succeeds iffexpris not a reference to a Cocoa object.refuteMissing(expr): a synonym forassertNotEqual(missing value, expr).assertNull(expr): a synonym forassertEqual(null, expr).refuteNull(expr): a synonym forassertNotEqual(null, expr).assertEqualAbsError(e1, e2, delta): succeeds iff|e1-e2| <= delta.assertEqualRelError(e1, e2, eps): succeeds iff|e1-e2| <= min(|e1|,|e2|) * eps.assertReference(x)orshouldBeReference(x): succeeds iffxis a reference.assertNotReference(x)orshouldNotBeReference(x): succeeds iffxis not a reference.assertInstanceOf(aClass, expr): succeeds iff the class ofexpris equal toaClass.refuteInstanceOf(aClass, expr): succeeds iff the class ofexpris notaClass.assertKindOf(aClass, expr): succeeds iffexpror any of its ancestors belongs toaClass.refuteKindOf(aClass, expr): succeeds iff neitherexprnor any of its ancestors belong toaClass.assertInheritsFrom(a, b): succeeds iffb(directly or indirectly) inherits froma.refuteInheritsFrom(a, b): succeeds iffbdoes not inherit froma.
Some of the assertions take a textual message as an argument (msg parameter),
which is printed when the assertion fails.
A clarification is in order for the last three types of assertions. Consider the following two scripts:
script A
property class : "Father"
end script
script B
property parent : A
property class : "Child"
end script
Then, these assertions must succeed:
assertInstanceOf("Father", A)
assertInstanceOf("Child", B)
refuteInstanceOf("Father", B)
assertKindOf("Father", B)
refuteInstanceOf(script, A)
assertKindOf(script, A)
assertInheritsFrom(A, B)
refuteInheritsFrom(B, A)
Related unit tests can be grouped together into a script that must
inherit from TestSet(me). One advantage of grouping
tests is that you may define setUp() and tearDown() operations
that are automatically executed before and after each unit test, respectively.
Such handlers can be used for initialization of
data structures and clean up operations, and help ensure that each unit test
is not affected by the behavior of the others.
Note that the names of the scripts are used in the output. For this reason, you
may want to use short sentences enclosed between vertical bars as script names,
as it was done in the example above. Alternatively, you may define the name
property of the script explicitly.
GNU GPL, see COPYING for details.
Copyright © 2013–2023 Lifepillar, 2006 Nir Soffer
