Tutorial on using MathOO
This is a basic tutorial about using MathOO, the internal structure of MathOO, and how MathOO works.
Content |
Introduction
In this tutorial, I will teach the basic of MathOO by writing a simple UnitTest class, use it to test the functionality of MathOO itself.
Basics
MathOO adds object orientation to Mathematica. Therefore this tutorial assumes you understand basic concepts of object-oriented programming.
To use MathOO, you first need to run:
Needs["MathOO`"]
In order to load the library and necessary functions.
The most important concept in OO is class. So, let's define a class first.
NewClass[UnitTest];
This defines UnitTest to be a new class.
Every class needs to have its own constructor (or any of its parents). Therefore let us define one first:
UnitTest.$init$[self_, file_: Null] := (self.command =
If[file === Null, {},
ReadList[file, Record, RecordSeparators -> {"\n\n"}][[2 ;;]]];
);
The constructor name is called $init$. $name$ is a convention used in MathOO. It indicates the simple is for internal use. It is just analogous to the constructor __init__ in Python. For your own private method, use $method instead. MathOO does not have the concept of private method, and it's up to you to follow the convention.
The above code define the UnitTest.$init$ to be a function with two variables: self and file. self stands for the object itself. For every class method, it is called with the object as the first argument. It is also a convention to use self as the object itself, as in Python too. file is an optional argument. If supplied, the function will look for the file, open it as text file, and split the file into records with "\n\n" as the split characters. Each of the record contributes to one test. And all tests are stored in the object attribute self.command.
UnitTest.addTest[self_, e_] := (AppendTo[self.command, e])
Now define another function UnitTest.addTest, so that you can add individual test as string.
UnitTest.run[self_] := Module[{l, fail, u},
fail = {};
Do[
e = Catch[ToExpression[c]];
If[e =!= True, AppendTo[fail, c]]
, {c, self.command}];
l = Length[self.command];
If[Length[fail] == 0, Print["All Tests Past!"], Print[fail]];
Print[ToString[l - Length[fail]] <> "/" <> ToString[l] <>
" tests past."]
]
To run the test, we need to define the function UnitTest.run. This function convert each of the string stored in self.command, and then evaluate it using ToExpression. Each test should output the value True, otherwise, it is considered failed. This function will print out the failed tests, and the number of tests past.
Usage of UnitTest
UnitTest can be used in two ways:
Using a file
Create a new package file (test.m) using Mathematica, the paste the following code into it and save.
BeginPackage["Testing`", {"MathOO`"}];
NewClass[h];
g;
Begin["`Private`"];
static[h.c];
h.c[x_] := x^2;
h.$init$[self_]:=Return[];
g = new[h][];
g.a=1;
g.b=2;
g.d=3;
End[];
EndPackage[];
h.c[5] == 25
g.a==1
g.b==2
g.d==3
g.c[6]==36
o = Object;
NewClass[A1, o];
NewClass[B1, o];
NewClass[C1, o];
NewClass[D1, o];
NewClass[E1, o];
NewClass[K1, A1, B1, C1];
NewClass[K2, D1, B1, E1];
NewClass[K3, D1, A1];
NewClass[Z, K1, K2, K3];
Z["$parentOrder$"] == {K1, K2, K3, D1, A1, B1, C1, E1, Object}
a={1,2};b={3,4};a.b==11
A1.a={3,4};A1.a.b==25
K1.g = {1, 2, 3};
K1.g[[2]] = 5;
K1.g == {1, 5, 3}
K1.g=.;
ToExpression[K1["g"],StandardForm,ValueQ]==False
a=new[Object][];
a.b=5;
u=a["b"];
delete[a.b];
Catch[a.b]=="No attributes Error :b" && !ToExpression[u,StandardForm,ValueQ]
a.b=new[Object][];
a.b.c=5;
delete[a.b.c];
Catch[a.b.c]=="No attributes Error :c"
Now, each of the empty line indicates an individual test.
In another notebook, type:
unit = new[UnitTest]["test.m"];
unit.run[];
It will output:
All Tests Past!
12/12 tests past.
Showing that all the tests past.
Adding individual test
Now, you can add individual test like this:
unit.addTest["x=new[Object][];
x.b=1;
x.b==1"];
Your test entered must be a string. Therefore if your test code has special characters such as ", they needed to be escaped, which I found quite troublesome.
Please login to post comment.