============================================================================= Testilence Library Reference ============================================================================= :Author: Roman Neuhauser :Contact: neuhauser@sigpipe.cz :Copyright: This document has been placed in the public domain. .. contents:: Overview ======== The library code is organized into six *circuits* (with some overlaps): testing, organization, execution, evaluation, reporting, and presentation. The testing circuit contains these important classes: `Tence_TestCase`_, *Tence_Assertion* (there's more but those are private parts). Organization comprises `Tence_TestSuite`_, `Tence_TestCase`_ classes, and the `Tence_TestCollection`_ interface. Execution includes the `Tence_RunnableTest` interface, and the *Tence_TestCaseClass* class. The evaluation, reporting, and presentation circuits are still too immature for documentation. `Tence_TestCase`_ is an abstract base class you're welcome to use as the parent of your test cases. However, any class that implements `Tence_RunnableTest`_ (and optionally `Tence_TestCollection`_) will do. `Tence_TestCase`_ provides a handful of assertion methods and provides a very concise interface for exception testing. *Tence_TestCaseClass* helps keep the number of non-assertion methods in `Tence_TestCase`_ as low as possible, a sort of proxy for `Tence_TestCase`_, identifies test methods in the test case instance. *Tence_Assertion* transports details of test method execution from the case into outside world. Instances of this class are virtually invisible to normal Testilence users, the class is mentioned here to prevent confusion later as it appears a lot in the *Tence_TestCase*'s synopsis. Test Results ++++++++++++ Possible test results are: * success * failure * exception * defect A "test" consists of calls to `setUp()`_, the test method, and `tearDown()`_. All three are considered during evaluation of the test, the formula is: 1. if `setUp()`_ or `tearDown()`_ threw, the test was defective, else 2. if the test method threw, and it was an expected exception (see `willThrow()`_), the test was successful, else 3. if the test method threw, but a different exception class was expected, the test failed, else 4. if the test method threw and no exception was expected, the result is an exception, else 5. if an exception was expected but not thrown, the test failed, else 6. if the test method returned a *Tence_Assertion*, that object defines whether the test was a success or a failure, else 7. the test was defective .. _willThrow() : `void Tence_TestCase::willThrow($type)`_ Public Components ================= Tence_RunnableTest ++++++++++++++++++ Interface through which the tests are run. _`void Tence_RunnableTest::run(Tence_Reporter $reporter)` Tence_TestCollection ++++++++++++++++++++ Interface for access to components of a composite test. _`Tence_RunnableTest[] Tence_TestCollection::getTests()` Tence_TestMethod ++++++++++++++++ :implements: `Tence_RunnableTest`_ _`Tence_TestMethod::__construct(Tence_TestCaseClass $tcc, ReflectionMethod $rm)` *$rm* must contain a method of the class wrapped in *$tcc*. _`void Tence_TestMethod::run(Tence_Reporter $reporter)` Constructs a new instance using *$tcc* and calls the method passed in *$rm*. Result of the invocation is passed to *$reporter*. Tence_TestCase ++++++++++++++ :implements: *Tence_RunnableTest*, *Tence_TestCollection* Abstract base for test case classes. This class is intended to provide comfortable environment for robust tests. To this end, *Tence_TestCase* offers a set of `assertion methods`_. A test case class inherits *Tence_TestCase*. It can define any number of `test methods`_, and optionally either or both of `setUp()`_ and `tearDown()`_. It **should not** define any constructor or destructor methods: the library is free to create and destroy suite and case instances without actually running them. Execution --------- :: void Tence_RunnableTest::run(Tence_Reporter $reporter) For each `test method`_, a new instance of this class is created, `setUp()`_ is called, then the test method, and finally `tearDown()`_. After tearDown(), the environment is put back into the same state it was in before setUp(). At present, at least global variables and the current working directory are reset to their pre-setUp() values. .. _test method: `test methods`_ Constructor and Destructor -------------------------- :: public final function __construct() public final function __destruct() Instances of Tence_TestCase's subclasses must be default constructible, and carry no state outside of the `setUp()`_-`tearDown()`_ interval. Tence_TestCase has final constructor and destructor to enforce this policy. .. _setUp() : `setUp() and tearDown()`_ .. _tearDown() : `setUp() and tearDown()`_ Test Methods ------------ :: public Tence_Assertion Tence_TestCase::testXXX() Any public nullary method whose name begins with "test" is considered a test method, and must return an instance of *Tence_Assertion*. Failing to do so results in the test method being marked as defective at runtime. setUp() and tearDown() ---------------------- :: public void Tence_TestCase::setUp() public void Tence_TestCase::tearDown() *setUp()* and/or *tearDown()* can be used for setup and cleanup tasks common to all test methods of the test case. *setUp()* is called before every test method, *tearDown()* afterwards, both on the same instance as the test method. If *setUp()* throws, *tearDown()* is run immediately. The test method is skipped. If either of these two methods throws, the test method is marked as defective. Exceptions thrown from *setUp()* mute all exceptions thrown from *tearDown()*. Assertion Methods ----------------- .. note:: None of the *assertFoo()* methods performs any type conversions on the tested values. This eliminates a few false negatives: for example, 0 == false, but their string representations differ drammaticaly ("0" vs. ""); the sooner this kind of things is caught the better. *assertTrue(1)* will fail, as will *assertEquals(1, "1")*! _`Tence_Assertion Tence_TestCase::assertTrue($bool, $msg = '')` Checks that *$bool* is ``true``. _`Tence_Assertion Tence_TestCase::assertFalse($bool, $msg = '')` Checks that *$bool* is ``false``. _`Tence_Assertion Tence_TestCase::assertEquals($exp, $act, $msg = '')` Checks that *$act* equals *$exp*. Instances of the same class are compared by value (using the == operator). _`Tence_Assertion Tence_TestCase::assertSame($exp, $act, $msg = '')` Checks that *$act* equals *$exp*. Instances of the same class are compared by identity (using the === operator). _`Tence_Assertion Tence_TestCase::assertNull($any, $msg = '')` Checks that *$any* is ``null``. _`Tence_Assertion Tence_TestCase::assertNotNull($any, $msg = '')` Checks that *$any* is not ``null``. _`Tence_Assertion Tence_TestCase::assertIsA($o, $class, $msg = '')` Checks that *$o* is an instance of *$class*. _`Tence_Assertion Tence_TestCase::assertMatches($re, $val, $msg = '')` Checks that *$val* matches the Perl-compatible regular expression *$re*. _`void Tence_TestCase::willThrow($type)` Alias: `void Tence_TestCase::setExpectedException($type)` Iff the code following the call of this method throws an exception that is instanceof *$type*, the test method will "return" successful assertion. All other outcomes cause a failure. Actual return value of this test method (if any) will be ignored. _`void Tence_TestCase::run(Tence_Reporter $reporter)` Calls every public method whose name begins with ``test``. Result of each invocation is passed to *$reporter*. _`Tence_RunnableTest[] Tence_TestCase::getTests()` Returns an array of Tence_TestMethod_ instances, one for each test method. Utility methods --------------- _`Tence_util_TempFile Tence_TestCase::mkstemp($dir, Tence_util_FilenameGenerator $gen = null)` Returns a Tence_util_TempFile_ instance. _`Tence_util_TempDir Tence_TestCase::mkdtemp($dir, Tence_util_FilenameGenerator $gen = null)` Returns a Tence_util_TempDir_ instance. Tence_util_TempFile +++++++++++++++++++ This class provides safe temporary files. The file is created in the constructor with:: fopen(..., 'x+') which should translate to open(..., O_EXCL|O_CREAT), and removed in the destructor. _`Tence_util_TempFile::__construct($dir, Tence_util_FilenameGenerator $generator = null)` $dir (falls back to getenv("TMPDIR") and "/tmp" if null) is used as the directory component of the path of the file being created. $generator defaults to a fresh instance of Tence_util_UniqueFilenameGenerator. Throws RuntimeException if $dir is wrong, or if fopen() fails. Tence_util_UniqueFilenameGenerator throws Tence_util_GeneratorExhausted if a unique filename cannot be found within the configured number of attempts. _`resource Tence_util_TempFile::fd()` Returns descriptor for the underlying file, open for reading and writing. _`string Tence_util_TempFile::path()` Returns path to the underlying file. _`Tence_util_TempFile::__destruct()` Unlinks the underlying file and closes the associated descriptor. Tence_util_TempDir ++++++++++++++++++ This class provides temporary directories. The directory is created in the constructor, and recursively removed in the destructor. _`Tence_util_TempDir::__construct($dir, Tence_util_FilenameGenerator $generator = null)` $dir (falls back to getenv("TMPDIR") and "/tmp" if null) is used as the directory component of the path of the directory being created. $generator defaults to a fresh instance of Tence_util_UniqueFilenameGenerator. Throws RuntimeException if $dir is wrong, or if mkdir() fails. Tence_util_UniqueFilenameGenerator throws Tence_util_GeneratorExhausted if a unique filename cannot be found within the configured number of attempts. _`string Tence_util_TempDir::path()` Returns path to the underlying directory. _`Tence_util_TempDir::__destruct()` Removes the underlying directory recursively. Tence_TestSuite +++++++++++++++ _`Tence_TestSuite & Tence_TestSuite::add(Tence_RunnableTest $test)` Adds *$test* to the suite. Returns *$this*. _`void Tence_TestSuite::run(Tence_Reporter $reporter)` Calls *run($reporter)* on every *$test* it contains. _`Tence_RunnableTest[] Tence_TestSuite::getTests()` Returns an array of all *$tests* added so far. .. target-notes:: .. section-numbering:: .. vim: ft=rst