Testing and Debugging
Prerequisites: Packages and paclets
Messages
When something goes wrong, the language prints a message and usually returns a result anyway:
1/0
Power::infy: Infinite expression 1/0 encountered.
ComplexInfinity
Messages are named symbol::tag. Quiet[expr] suppresses them;
Check[expr, failValue] returns failValue if any message was issued:
Check[1/0, "failed"]
Power::infy: Infinite expression 1/0 encountered.
failed
Your own messages
safeSqrt::neg = "Argument `1` should be non-negative.";
safeSqrt[x_?NonNegative] := Sqrt[x]
safeSqrt[x_] := (Message[safeSqrt::neg, x]; $Failed)
safeSqrt[16]
safeSqrt[-4]
4
safeSqrt::neg: Argument -4 should be non-negative.
$Failed
`1` in a message template is replaced by the first extra argument to
Message. Returning $Failed — or a structured Failure[...] object —
makes errors easy to detect with FailureQ.
Enclose and Confirm
Confirm functions stop a computation at the first problem, and
Enclose catches it and returns a Failure:
ratio[a_, b_] := Enclose[
ConfirmAssert[b != 0, "b must be nonzero"];
a/b
]
ratio[6, 4]
FailureQ[ratio[1, 0]]
3/2
True
The failure object records the message and where it happened, which is much easier to debug than an unexpected symbolic result further down the line.
Looking inside a computation
Echo[expr, "label"]prints the labelled value and returns it, so you can drop it into the middle of any expression.Trace[expr]lists evaluation steps;TracePrintprints them as they happen.Printworks anywhere;Monitor[loop, i]shows a live progress value.- The VS Code extension and Wolfram Workbench provide breakpoints.
Unit tests
VerificationTest[input, expected] evaluates input and checks it against
expected — and that no unexpected messages appear. TestReport runs a
group of tests:
report = TestReport[{
VerificationTest[circleArea[2], 4 Pi],
VerificationTest[squareArea[3], 9],
VerificationTest[1/0, ComplexInfinity, {Power::infy}]
}];
report["ReportSucceeded"]
True
- The third argument lists the messages a test expects — here the division-by-zero message.
- Put tests in a
.wltfile and runTestReport["tests.wlt"]from a script, so your continuous-integration pipeline can run them withwolframscript. - Version 13.3 added
TestCreateandTestEvaluatefor creating and running test objects separately;VerificationTeststill works everywhere. - These tests use
circleAreaandsquareAreafrom the "Packages and Paclets" lesson — loadGeometry.wlfirst.