Category Archives: Python

Using Hypothesis with Factory Boy

I gave a talk on the Hypothesis Django Integration last night (video and transcript here). I got some questions asking about integration with Factory Boy.

My answer at the time was that I’ve thought about adding explicit support but there’s nothing to stop you from doing it yourself. I’d like to amend that: There’s nothing to stop you from doing it yourself and it’s so easy to do that I can’t actually imagine how I would improve it with explicit support.

Both Factory Boy and Hypothesis are designed along a “we’re a library, not a framework” approach (the Hypothesis django integration goes a little further in the direction of a framework than I’d like by requiring a custom test runner, but fortunately factory boy does not), so they don’t interfere with eachother. Further, factory boy is set up to take arbitrary values, Hypothesis is set up to provide them, so you can easily feed the latter into the former.

For example, the following defines a strategy that uses a factory boy UserFactory object to parametrize over unsaved user objects with an arbitrary first name:

from hypothesis import given
from hypothesis.strategies import builds, text
from hypothesis.extra.django import TestCase
from myfactories import UserFactory
 
class TestUser(TestCase):
    @given(builds(UserFactory.build, first_name=text(max_length=50)))
    def test_can_save_a_user(self, user):
        user.save()

Both factory boy and Hypothesis are designed to play well with others, so unless I’m missing something, nothing specific seems necessary to make them play well with each other. This is how it should work.

The only thing that I can imagine people conceivably wanting custom support for is auto deriving strategies for factory boy instances that are using random fields filled by fake factory. It wouldn’t be too hard to do, but I’m not sure it’s worth it. Honestly if you’re doing randomized testing like that, you should be using Hypothesis and its existing fake factory integration to feed your factories instead. It will be a much better experience.

This entry was posted in Hypothesis, Python on by .

Using tmux to test your console applications

Edit to add: The ideas in this post are now implemented in a library. Feel free to read this post for understanding the concepts, but you’re probably better off just using that.

If you’ve noticed that there haven’t been 5000 words of blogging and seven Hypothesis releases in the last week and wondered whether I was dead, fear not. I was just on a fort.

The theme of this fort was that we were going to work on a C project. People made the mistake of listening to me, and one thing lead to another, and the result is Conch, a security free curses interface to our terrible Twitter clone, Bugle. Here’s a sneak peek:

conch

This post is mostly not about Conch, except that working on it was what lead to this concept.

We used check for testing a lot of the implementation, which was fine if a little laborious. However testing the front end (oh god, why do we have front end code written in C?) proved challenging. ncurses was not our friend here.

I tried using pexpect for this, which is like expect but written in python instead of TCL, but ran into a bunch of problems. It has an ANSI virtual terminal, but for whatever reason (this might have been my fault) it got very confused and ended up with lots of problems with partial drawing of things and leaving the screen in a wrong state.

So I put my thinking cap on, read some man pages, and applied some twisted imagination to the problem and came up with a solution that works great, albeit at some small cost to my dignity and sense of taste.

The solution is this: What I need is a robust virtual terminal I can control and inspect the state of.

Fortunately I have one. It’s called tmux.

Tmux is pretty great. It has a whole bunch of functionality, is a rock solid virtual terminal that is widely used with a wide variety of programs, and you can control it all externally via the command line. Putting these all together lead to a bunch of primitive operations out of which I could basically build selenium style testing for the console.

I’m still figuring out the details. When I do I’ll probably turn this into a library for testing console applications rather than the current ad-hoc thing I have, but basically there’s a relatively small set of operations you can build this testing out of:

  1. First we allocate a unique ID for our test. This should be long and random to avoid conflicting with existing sessions. Henceforth it will be called $ID.
  2. “tmux -L $ID  new-session -d <your shell command>” will start your program running in a fresh tmux session under your id. The -d is necessary because you will not be starting this from a controlling terminal in your program, so you want it to start detached. If you want you can specify width and height with -x and -y respectively.
  3. At the end, “tmux -L $ID kill-server” will shut down all sessions in your test tmux server, including the child processes.
  4. In order to capture the current contents of your tmux session you can run: “tmux -L $ID capture-pane; tmux -L $ID show-buffer; tmux -L $ID delete-buffer”. This will save a “screenshot” of the currently active pane (of which there is only one if you’ve just used these commands) to a new paste buffer, print the paste buffer to stdout, then delete the buffer.
  5. In order to send key presses to the running program you can use “tmux -L $ID send-key <some-char>”. These can either be ascii characters or a variety of control ones. e.g. PageUp, PageDown and Enter do what you expect. Adding C- as a modifier will hold down control, so e.g. C-c and C-d would be Control-c and Control-d with their usual interpretations (send an interrupt to the running program, send EOF).
  6. In order to send non-ascii or larger text you can use do “tmux -L $ID set-buffer <my text>; tmux -L $ID paste-buffer; tmux -L $ID delete-buffer”, which will set a paste buffer, paste it to the active pane, and then delete the buffer.

(Some of the above is not actually what I did, because I figured out some better ways using commands I’d previously missed while writing this post).

The main things that are hard to do with this, and why for now this is a blog post rather than a piece of open source software, is getting the PID and exit code out for the program you’ve started and resizing the window. I know how to do both of those (running a manager process and starting inside a pane respectively), but it’s fiddly and I haven’t got the details right. When I do, expect all of the above to be baked into a library.

This entry was posted in Code, Python on by .

The era of rapid Hypothesis development is coming to an end

Don’t panic. This is not an announcement of my abandoning the project. Hypothesis still has a long way to go, and I 100% intend to be working on getting it there.

What this is an announcement of is of my continued existence in a market economy and my tragic need to acquire currency in order to convert it into food and accommodation.

I haven’t been making a big deal of it, so some of you might be surprised to learn that the reason Hypothesis development has been so rapid for the last 6 months is that I’ve been working on it full time unpaid. It’s not so much that I took time off to write Hypothesis as that I had the time off anyway and I thought I’d do something useful with it. Hypothesis is that something useful.

I would love to continue working on Hypothesis full time. But the whole “unpaid” thing is starting to become not viable, and will become critically non-viable as soon as I move back to London.

So I’m going to need money.

I will do something more organised in the next month, but for now if you are a company or individual interested in paying me to do any of the following, I would very much like to hear from you:

  • Sponsored Hypothesis development (this can include paying for implementing specific features if you want)
  • Integration work getting Hypothesis to work well your testing environment
  • Training courses on how to use Hypothesis
  • Anything else Hypothesis related

If the above sounds interesting, please email me at [email protected].

If no money to continue working on Hypothesis is forthcoming, Hypothesis development will absolutely continue, but at a greatly reduced rate. The current development cycle is approximately a minor version a week. This will likely go down to at most a minor version every month, more likely a minor version every two. This would be a shame, as I have a bunch of exciting features I still want to work on, and then I need to tie everything together into a coherent 2.0 release. With full time work I would project that to happen end of this year, without I can’t really make any predictions at the moment.

This entry was posted in Hypothesis, Python on by .

Constraint based fixtures with Hypothesis

A common experience when writing database backed web applications (which I hear is a thing some people like to do) is that rather than laboriously setting up each example in each test you use a set of fixtures – standard project definitions, standard users, etc.

Typically these start off small but grow increasingly unwieldy over time, as new tests occasionally require some additional detail and it’s easier to add little things to an existing fixture than it is to create one afresh.

And then what happens is that it becomes increasingly unclear which bits of those fixtures actually matter and which of them are just there because some other test happened to need them.

You can use tools like factory_boy to make this easier, but ultimately it’s still just making the above process easier – you still have the same problems, but it’s less work to get there.

What if instead of having these complicated fixtures your tests could just ask for what they want and be given it?

As well as its use in testing, Hypothesis has the ability to find values satisfying some predicate. And this can be used to create fixtures that are constraint based instead of example based. That is: You don’t ask for the foo_project fixture, you instead say “I want a project whose owner is on the free plan”, and Hypothesis gives it to you:

from hypothesis import find
from hypothesis.extra.django.models import models
from mymodels import Project, User
 
def test_add_users_to_free_project():
    project = find(
        models(Project, owner=models(User)),
        lambda x: x.owner.plan == "free")
    do_some_stuff_with(project)

And that’s basically it. You write fixture based tests as you normally would, only you can be as explicit as you like as to what features you want from the fixtures rather than just using what happens to be around.

It’s unclear to me whether this is ever an improvement on using Hypothesis as it is intended to be used – I feel like it might work better in cases where the assumptions are relatively hard to satisfy, and it’s probably better for things where the test is really slow – but what is the case is that it’s a lot less alien to people coming from a classical unit testing background than Hypothesis’s style of property testing is, which makes it a convenient gateway usage mode for people who want to get their feet wet in this sort of testing world without having to fundamentally change the way that they think in order to test trivial features.

There are a bunch of things I can do to make this sort of thing better if it proves popular, but all of the above works today. If it sounds appealing, give it a try. Let me know how it works out for you.

Edit to add: I’ve realised there are some problems with using current Hypothesis with Django like this unfortunately. Specifically if you have unique constraints on models you’re constructing this will not work right now. This concept works fine for normal data, and if there’s interest I’m pretty sure I can make it work in Django, but it needs some further thought.

This entry was posted in Hypothesis, Python on by .

If you want Python 2.6 support, pay me

This post is both about the actual plan for Hypothesis and also what I think you should do as a maintainer of a Python library.

Hypothesis supports Python 2.7 and will almost certainly continue doing so until it hits end of life in 2020.

Hypothesis does not support Python 2.6.

Could Hypothesis support Python 2.6? Almost certainly. It would be a bunch of work, but probably no more than a few weeks, maybe a month if things are worse than I expect. It would also slow down future development because I’d have to maintain compatibility with it, but not to an unbearable degree given that I’ve already got the machinery in place for multiple version compatibility.

I’m not going to do this though. I’m doing enough free labour as it is without supporting a version of Python that is only still viable because a company is charging for commercial support for it.

I’m sorry, I misspoke. What I meant to say is that I’m not going to do this for free.

If you were to pay me, say, £15,000 for development costs, I would be happy to commit to providing 2.6 support in a released version of Hypothesis, followed by one year in which there is a version that supports Python 2.6 and is getting active bug fixes (this would probably always be the latest version, but if I hit a blocker I might end up dropping 2.6 from the latest and providing patch releases for a previous minor version).

People who are still using Python 2.6 are generally large companies who are already paying for commercial support, so I think it’s perfectly reasonable to demand this of them.

And I think everyone developing open source Python who is considering supporting Python 2.6 should do this too. Multi version library development is hard enough as it is without supporting 2.6. Why should you work for free on something that you are really quite justified in asking for payment for?

This entry was posted in Hypothesis, Python, Uncategorized on by .