Test Helpers

The framework includes a few nuggets to support unit testing using unittest.

WizLibTestCase

A subclass of unittest.TestCase to simplify patching inputs and outputs.

Because WizLib applications sometimes depend on user interaction, and other times depend on a stream on standard input, unit testing can require complicated patching. Inherit from WizLibTestCase to make it easier.

Here's an example of how to use it. In this example, we send the word 'laughter' to the standard input stream and capture standard output in a variable for assertion.

# Inherit from WizLibTestCase - get everything in TestCase plus some
class DummyTest(WizLibTestCase):

    # Test function - ass
    def test_input_stdin(self):

        # Use with instead of decorators (to take advantage of 'as') and combine them (if you like that style)
        with \
                self.patch_stream('laughter'), \
                self.patchout() as o:

            # Get going with the test
            DummyApp.start('dance')
            o.seek(0)
        self.assertIn('laughter', o.read())

The actual methods that can be used are:

  • patch_stream(val: str) - Patch stream input such as pipes for stream handler
  • patch_ttyin(val: str) - Patch input typed by a user in shell ui
  • patcherr() - Capture output from standard error
  • patchout() - Capture output from standard output

They are convenience methods; feel free to patch those objects separately if you prefer.

Fake values

Framework-aware mock objects

ConfigHandler.fake

Generates a fake WizLib configuration for testing. Example:

    def test_fake_config(self):
        a = DummyApp()
        a.config = ConfigHandler.fake(dummy_vehicle='boat')
        c = DriveCommand(a)
        r = c.execute()
        self.assertIn('Driving a boat', r)

Note that the keys passed to the fake method contain hyphens, where values are referenced using hyphens, for example:

self.app.config.get('dummy-vehicle')

StreamHandler.fake

Generates a fake standard input stream. Example:

    def test_fake_input(self):
        a = DummyApp()
        a.stream = StreamHandler.fake('madly')
        c = DanceCommand(a)
        r = c.execute()
        self.assertEqual('Dancing madly', r)

Testing commands

Since much of the framework-specific functionality in a WizLib app lives in commands, some special guidelines and provisions apply.

Testing command execution only

To test only the execution of a command's functionality (independent of argument parsing), instantiate the command directly. It still requires a WizApp object as the first parameter, and arguments as successive parameters. Example:

    def test_only_command(self):
        a = DummyApp()
        c = MathCommand(a, value=10.0)
        r = c.execute()
        self.assertEqual(6.0, r)

Testing a command with parsing

The WizLibApp.parse_run method provides a quick entry point into the parsing and execution of a full command, without having to go through the class-level start/initialize steps. Just pass in the command and its arguments as function arguments, and the selected command will run. Used to test not just the functionality of the command itself, but also that arguments are correctly parsed. Example:

    def test_parse_run(self):
        with self.patchout() as o:
            DummyApp().parse_run('draw', '-c', 'straight')
        o.seek(0)
        self.assertIn('Curve was straight', o.read())