Testing
A minimal unit test for a function. We define a tiny add function and check it against a couple of expected results. Most languages ship a test idiom in the standard library or runtime; where none exists, an assertion that aborts on failure plays the same role.
sub add($a: Int, $b: Int): Int {
$a + $b
}
sub assert_eq($actual: Int, $expected: Int, $name: Str): Unit {
if $actual == $expected {
print("ok - $name")
} else {
panic("FAIL $name: expected $expected, got $actual")
}
}
sub main() {
assert_eq(add(2, 3), 5, "adds positives")
assert_eq(add(-1, 1), 0, "adds to zero")
}guji (v0.1-alpha) has no dedicated test framework yet, so an idiomatic check is an assert_eq helper built from the prelude's print and the panic intrinsic (§11.2, §15.4). A passing case prints a TAP-style ok line; a mismatch calls panic, which writes the message to stderr and aborts with a non-zero exit code. The whole file runs as an ordinary main, so the same program is both the test and its runner - and since guji compiles, you can run it with the interpreter (guji file.guji) or build a native binary (guji build -o test file.guji), which behave identically.
package add
func Add(a, b int) int {
return a + b
}
// add_test.go
package add
import "testing"
func TestAdd(t *testing.T) {
cases := []struct {
name string
a, b int
want int
}{
{"adds positives", 2, 3, 5},
{"adds to zero", -1, 1, 0},
}
for _, c := range cases {
if got := Add(c.a, c.b); got != c.want {
t.Errorf("%s: Add(%d, %d) = %d, want %d", c.name, c.a, c.b, got, c.want)
}
}
}Go's testing package is part of the standard toolchain: any TestXxx(t *testing.T) function in a _test.go file is discovered and run by go test. The idiomatic style is table-driven, iterating over a slice of cases and calling t.Errorf to record a failure without halting the rest of the loop. No assertion library is needed, only the t handle.
let add a b = a + b
let check name actual expected =
if actual = expected then
Printf.printf "ok - %s\n" name
else
failwith (Printf.sprintf "FAIL %s: expected %d, got %d" name expected actual)
let () =
check "adds positives" (add 2 3) 5;
check "adds to zero" (add (-1) 1) 0Real OCaml projects reach for a framework such as Alcotest or ppx_inline_test, but the language core already gives a self-contained check: structural equality = plus failwith, which raises Failure to abort with a message on a mismatch. Each check prints an ok line when the assertion holds. Running the executable is the test run, exiting non-zero on the first failure.
module Main (main) where
import Control.Monad (unless)
add :: Int -> Int -> Int
add a b = a + b
check :: String -> Int -> Int -> IO ()
check name actual expected =
unless (actual == expected) $
error ("FAIL " ++ name ++ ": expected " ++ show expected ++ ", got " ++ show actual)
main :: IO ()
main = do
check "adds positives" (add 2 3) 5
check "adds to zero" (add (-1) 1) 0
putStrLn "all tests passed"Production Haskell uses HUnit, tasty, or property testing with QuickCheck, but the pure core plus base is enough for a minimal check. check compares the result with == and, on a mismatch, calls error, which throws and aborts with a non-zero exit. The pure add is tested by an IO driver in main; reaching putStrLn means every assertion held.
use strict;
use warnings;
use Test::More tests => 2;
sub add { my ($a, $b) = @_; return $a + $b; }
is(add(2, 3), 5, 'adds positives');
is(add(-1, 1), 0, 'adds to zero');Test::More is the standard Perl testing module and emits TAP (Test Anything Protocol), the output format harnesses like prove understand. is compares actual against expected and prints ok/not ok with the description, while the tests => 2 plan guards against the script dying early and silently skipping checks. The file is run directly with perl, or under prove for a summary.
use Test;
sub add($a, $b) { $a + $b }
plan 2;
is add(2, 3), 5, 'adds positives';
is add(-1, 1), 0, 'adds to zero';Raku ships the Test module in core, so no install is needed, and like Perl it emits TAP. plan 2 declares how many assertions to expect, and is checks equality and reports each result with its label. The file runs directly with raku, or under prove6/zef test inside a distribution.
fn add(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn adds_positives() {
assert_eq!(add(2, 3), 5);
}
#[test]
fn adds_to_zero() {
assert_eq!(add(-1, 1), 0);
}
}Rust has a built-in test harness: functions marked #[test] are compiled and run by cargo test. They live in a #[cfg(test)] module so the test code is excluded from normal builds, and use super::* pulls the parent module's items into scope. The assert_eq! macro panics with a helpful diff on a mismatch, which the harness records as a failed test.
import unittest
def add(a, b):
return a + b
class TestAdd(unittest.TestCase):
def test_adds_positives(self):
self.assertEqual(add(2, 3), 5)
def test_adds_to_zero(self):
self.assertEqual(add(-1, 1), 0)
if __name__ == "__main__":
unittest.main()unittest is in the standard library: test methods named test_* on a TestCase subclass are auto-discovered and run. assertEqual reports a clear message when the values differ, and unittest.main() lets the file run directly as a test suite. Many projects prefer pytest for terser plain-assert tests, but unittest needs no dependencies.