Hy, Nose and Hypothesis

I recently came across a tool called Hypothesis that immediately sparked my interest. Their documentation describe it as:

Hypothesis is a Python library for creating unit tests which are simpler to write and more powerful when run, finding edge cases in your code you wouldn’t have thought to look for. It is stable, powerful and easy to add to any existing test suite.

Stable, powerful and easy to add are all words that I like. And if you know me, you quickly guessed that I wanted a Hy interface for this new shiny tool.

Continue reading

Testing with Hy and Nose

I have been using Nose for the longest time and it’s my go-to tool for running tests. Nose is very no-nonsense and has very sensible defaults (to me at least).

Writing a test in Hy that gets discovered and executed with Nose is pretty straightforward. One just needs a correct naming convention and everything happens more or less automatically. However, by applying some standard lisp practices, one can cut down amount of the code needed quite a bit. In this post, I’ll present how my style of writing tests have evolved over time and what kind of measures I took in order to write minimum amount of code.

Continue reading

Running nosetests for Hy

Getting nosetest to work with Hy was easier than I thought in the end. The trick I used was to create a Python module that will act as an entry point. In that module I first import Hy, which in turn lets me to import my test modules:

import hy
from .test_person_repository import *

After that I can run nosetests and end up with:

tuukka@new-loft:~/programming/python/sandvalley/src/sandvalley/tests$ nosetests
..
----------------------------------------------------------------------
Ran 2 tests in 0.015s

OK

Pretty nifty I must say. Having to import everything from modules in a entry point module is a bit hassle, but that’s something that I should be able to automate.

The same method can be used to call Hy code from Python program.

Tinkering with testing in Hy

I have been playing around with Hy more recently and started liking it a lot. I’m nowhere productive in coding with it, but I’m sure learning all kinds of new things.

Recently I decided to write some tests for Sandvalley project and came up with the following:

(import [sandvalley.tests.helpers [get-in-memory-connection]])
(import [sandvalley.person [save-person load-person]])
(import [sandvalley.database.schema [create-schema]])
(import [hamcrest [assert-that is- equal-to]])

(defn test-save-person []
  (let [[person {"id" None "name" "Pete"}]
        [connection (create-schema (get-in-memory-connection))]
        [saved-person (save-person person connection)]
        [loaded-person (load-person (get saved-person "id") connection)]]
    (assert-that (get loaded-person "name") (is- (equal-to "Pete")))))

(defn test-update-person []
  (let [[person {"id" None "name" "Pete"}]
        [connection (create-schema (get-in-memory-connection))]
        [saved-person (save-person person connection)]
        [loaded-person (load-person (get saved-person "id") connection)]]
    (assoc loaded-person "name" "Uglak")
    (save-person loaded-person connection)
    (let [[updated-person (load-person (get saved-person "id") connection)]]
      (assert-that (get updated-person "name") (is - (equal-to "Uglak"))))))

(if (= __name__ "__main__")
  (test-save-person)
  (test-update-person))

Pretty basic things, we create an empty in-memory database and do some saving, loading and updating on it. Nice thing is that I can use Hamcrest with asserts and the API does not stand out from rest of the code. The part I don’t like is

(assoc loaded-person "name" "Uglak")

, since there I’m changing loaded-person. I’ll probably end up writing a helper function that can combine two dictionaries and use it instead.

However, I haven’t been able to figure out how to run tests with Nose. If I could compile the code to bytecode, it should be possible. Hy project has tests written in Hy and apparently I can even run them with nose. However, when I tried to imitate what they are doing, I ended up getting funny errors deep inside hy2py. So in the meantime, I have settled on running tests from __main__. The drawback of course is that as soon as one of them fails, the execution halts.

Doctests

I have known about doctest for quite a while, but never got around to try them out. Today I wrote my first one:

def add_to_tick(self, cost):
    """
    Add cost of action to characters tick, while taking characters speed into account

    For example:
    >> pc = Character(None, None, None)
    >> pc.tick = 5
    >> pc.speed = 2
    >> pc.add_to_tick(5)
    15

    Args:
    cost: Cost of action in ticks

    Returns:
    New ticks
    """
    self.tick = self.tick + (self.speed * cost)
    return self.tick

After running it through nosetests –with-doctest –with-xunit and mangling the xml to html, I end up with:

pyherc.data.model.Character
add_to_tick Ok 0.093

Nothing really fancy and certainly nothing that I couldn’t achieve with normal unit tests. But the key to here is that I’m not testing the code, I’m testing the documentation (namely the code example). If I were to add a new parameter to the function and not update the example, the test would fail.

I’m most likely not going to use doctest very extensively, but maybe there are place or two to use it.