Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

We might be interested in starting to incorporate a unit test suite to our project, which is coded in Python (and it uses Redis, PostgreSQL and some third-party libraries, if that bears into the solution). The benefits we want to achieve are:

  1. Once the project is up to speed, we want to be able to specify new behavior quickly and efficiently, to help improve communication and team productivity. Read: We want BDD, but have already started coding without it.
  2. Excellent textual support (i.e. the tests can be read almost as natural text), so as to make it easier to write and read tests.
  3. Ability to automatically run tests (at the very least, to be able to include the running in a Bash script or something like that). We use Windows and Linux for development, and Linux servers, so Linux support is our primary requirement.
  4. Integration with github. I don't know if it is possible, but I've seen some projects in github which have a "Passing" or "Failing" status on them and it would be great to have that for our project.

What are good tools / libraries that can help us do this, and, most importantly, what are good ways to incorporate BDD into a Python project?

Thank you very much! Any suggestions are appreciated.

share|improve this question
1  
What has your research uncovered so far? –  Robert Harvey Jan 7 '13 at 16:05
1  
So far, I have found Behave (pypi.python.org/pypi/behave) which looks like a pretty good approach. I have also seen Lettuce (lettuce.it) which I also like. However, more than packages per se, I am interested in strategies or patterns to use. –  Juan Carlos Coto Jan 7 '13 at 17:47
add comment

3 Answers 3

up vote 2 down vote accepted

Try out pyspecs. Making tests easy to read and constantly running during development were two of my main goals in creating this project.

Test Code:

from pyspecs import given, when, then, and_, the, this

with given.two_operands:
    a = 2
    b = 3

    with when.supplied_to_the_add_function:
        total = a + b

        with then.the_total_should_be_mathmatically_correct:
            the(total).should.equal(5)

        with and_.the_total_should_be_greater_than_either_operand:
            the(total).should.be_greater_than(a)
            the(total).should.be_greater_than(b)

    with when.supplied_to_the_subtract_function:
        difference = b - a

        with then.the_difference_should_be_mathmatically_correct:
            the(difference).should.equal(1)

Console Output:

# run_pyspecs.py

  | • given two operands 
  |   • when supplied to the add function 
  |     • then the total should be mathmatically correct 
  |     • and the total should be greater than either operand 
  |   • when supplied to the subtract function 
  |     • then the difference should be mathmatically correct 

(ok) 6 passed (6 steps, 1 scenarios in 0.0002 seconds)
share|improve this answer
    
Any idea about the integration with Github? Thanks! –  Juan Carlos Coto Jul 21 '13 at 9:54
1  
Try this: stackoverflow.com/questions/13546097/… –  mdwhatcott Jul 22 '13 at 21:50
add comment

I've been working on a BDD framework called Contexts, inspired by C#'s Machine.Specifications.

Contexts encourages you to write descriptive user-centric sentences for your tests (which is what BDD is all about, really) by spreading out test-cases across a whole class. The arrange/act/assert phases of the test are put in individual short methods, and Contexts figures out which method is which based on their names.

A picture speaks a thousand words, so here's an example from the readme:

import requests

class WhenRequestingAResourceThatDoesNotExist:
    def given_that_we_are_asking_for_a_made_up_resource(self):
        self.uri = "http://www.github.com/itdontexistman"
        self.session = requests.Session()

    def because_we_make_a_request(self):
        self.response = self.session.get(self.uri)

    def the_response_should_have_a_status_code_of_404(self):
        assert self.response.status_code == 404

    def the_response_should_have_an_HTML_content_type(self):
        assert self.response.headers['content-type'] == 'text/html'

    def cleanup_the_session(self):
        self.session.close()

Contexts also has a number of modern features like parametrised tests, 'assertion-rewriting' (inspired by py.test), and a plugin framework.

I've used Contexts to test itself, as well as on a few other projects (even non-Python projects), and found it to yield understandable, behavioural tests at all levels of the testing triangle (unlike unittest which was not designed for acceptance testing, or Lettuce which was not designed for unit testing).

share|improve this answer
1  
Wonderful job with Contexts. I'm also a fan of mspec for my C# work. I think this should be the correct answer. Disclosure: I'm the author of pyspecs, which is currently the chosen answer for this question. –  mdwhatcott Mar 2 at 4:20
add comment

While there are BDD frameworks like lettuce or behave (which you better choose by their documentation and examples), you mentioned that you've started without that. So my answer will be related more to this situation.

Original BDD has started with fork of JUnit, which, instead of asking you to name your tests with "testSomething" asked you to name them "shouldDoSomething". That's how you were supposed to be kept focused on things.

So I went the same way in my project. I just started to name tests starting with "test_should_..." and try to give them descriptive names. That's how you're still doing BDD, you're still focused on what exactly should that test do, and it's easy to write something that will convert your test names into normal sentences (if you'll need to, of course). I find this approach a silver bullet since (especially in scripted languages) I never want to waste time on useless names (like test name in case of those BDD frameworks on top).

share|improve this answer
1  
This. From what I'm reading, Lettuce and Behave are higher-level BDD frameworks, like Cucumber, meant to capture scenarios discovered in conversation with business stakeholders. If you're just communicating with other devs, they can read code; don't worry about using a BDD tool. Any unit testing tool will do the job. I sometimes put my class-level Given, When, Then into comments. –  Lunivore Feb 17 '13 at 10:02
    
@Lunivore my point is that if you convert test name from "test_should_get_error_on_registering_user_with_empty_email" to text "Should get error on registering user with empty email" -- any person will understand what it means. Problem takes place when you have description that's too long, then your python test names will just look creepy (and Lettuce will look just fine). –  Konstantine Rybnikov Feb 18 '13 at 10:14
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.