554

I completed my first proper project in Python and now my task is to write tests for it.

Since this is the first time I did a project, this is the first time I would be writing tests for it.

The question is, how do I start? I have absolutely no idea. Can anyone point me to some documentation/ tutorial/ link/ book that I can use to start with writing tests (and I guess unit testing in particular)

Any advice will be welcomed on this topic.

user225312
  • 126,773
  • 69
  • 172
  • 181
  • 5
    It's never too late to write tests if that's you're intention. Better to have some than none for all that complain... – Asken Aug 09 '13 at 11:15
  • 4
    good resource I stumbled upon [https://www.jeffknupp.com/blog/2013/12/09/improve-your-python-understanding-unit-testing/](https://www.jeffknupp.com/blog/2013/12/09/improve-your-python-understanding-unit-testing/). As a newbie to python, I found it understandable. – ferry Jan 01 '16 at 17:38
  • 2
    The Hitchhiker's Guide to Python has a brief overview of tools for unit testing: http://python-guide-pt-br.readthedocs.io/en/latest/writing/tests/ – Anton Tarasenko Apr 17 '17 at 09:36
  • The previous comment should be rated higher, since the guide also has an example code repository on https://github.com/kennethreitz/samplemod which is a great place to get started, too. – setempler Dec 23 '17 at 20:11
  • Use `py.test`. `nose` and `nose2` are in maintenance mode. `unittest` requires more boiler-plate code compared to `py.test` and `py.test` is getting way more traction than the other frameworks. – alpha_989 Jan 28 '18 at 18:03
  • @AntonTarasenko : (broken link) https://python-docs.readthedocs.io/en/latest/writing/tests.html – Campa Sep 14 '21 at 08:51

7 Answers7

117

If you're brand new to using unittests, the simplest approach to learn is often the best. On that basis along I recommend using py.test rather than the default unittest module.

Consider these two examples, which do the same thing:

Example 1 (unittest):

import unittest

class LearningCase(unittest.TestCase):
    def test_starting_out(self):
        self.assertEqual(1, 1)

def main():
    unittest.main()

if __name__ == "__main__":
    main()

Example 2 (pytest):

def test_starting_out():
    assert 1 == 1

Assuming that both files are named test_unittesting.py, how do we run the tests?

Example 1 (unittest):

cd /path/to/dir/
python test_unittesting.py

Example 2 (pytest):

cd /path/to/dir/
py.test
GabLeRoux
  • 16,715
  • 16
  • 63
  • 81
Tim McNamara
  • 18,019
  • 4
  • 52
  • 83
  • 8
    I have heard about the simplicity of py.test at multiple places (http://docs.python-guide.org/en/latest/writing/tests/#py-test, https://docs.python.org/3.5/library/unittest.html#module-unittest, https://jeffknupp.com/blog/2013/12/09/improve-your-python-understanding-unit-testing/) Why is `unit-test` still included in the standard library, if `py.test` and `nose` provide the same functionality with much simpler interface? Is it just to provide backward compatibility, or does `unittest` have some advantages that `py.test` and `nosetest` can't provide? – alpha_989 Jan 28 '18 at 17:29
  • 4
    @alpha_989 The standard python library is not intended to contain the best tools available. That's what PyPI is for. The standard `unittest` package is still good enough. It is *standard* which means that it's kind of guaranteed to work well. Finally, anyone who uses your code doesn't need to install extra packages. – Jeyekomon Jul 06 '18 at 15:04
  • Hi, could you please tell how can I prevent `skip()`, `skipIf()` method from escaping the reason string. The problem is the output of the `skip()` or `skipIf()` decorator is joined at \n which I don't want. Please enlighten me! – Ayush Dec 25 '21 at 08:11
74

The free Python book Dive Into Python has a chapter on unit testing that you might find useful.

If you follow modern practices you should probably write the tests while you are writing your project, and not wait until your project is nearly finished.

Bit late now, but now you know for next time. :)

Tehscript
  • 2,556
  • 2
  • 13
  • 23
Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • 13
    I'd still say that if you want to refactor code that doesn't have unit tests, you should first write unit tests for it – Hubert Kario Nov 13 '14 at 15:19
  • 11
    Yeah, a lot of people who come to unittests for the first time hear what sounds like "well, it's kind of too late for your current project" from old hands: even if that's not what they actually meant to say, that's what newbies hear. It's like the Chinese proverb about planting a tree: the best time to start tests is at the beginning of a project; the second-best time to start tests is now! – J-P Nov 11 '16 at 11:22
  • 5
    Dive into Python link is broken... :-( – Scott Skiles Oct 19 '18 at 18:32
  • Hi, could you please tell how can I prevent `skip()`, `skipIf()` method from escaping the reason string. The problem is the output of the `skip()` or `skipIf()` decorator is joined at \n which I don't want. Please enlighten me! – Ayush Dec 25 '21 at 08:14
44

There are, in my opinion, three great Python testing frameworks that are good to check out:

  • unittest - module comes standard with all Python distributions
  • nose - can run unittest tests, and has less boilerplate.
  • pytest - also runs unittest tests, has less boilerplate, better reporting, and lots of cool extra features

To get a good comparison of all of these, read through the introductions to each at Start Here - Python Testing. There are also extended articles on fixtures, and more there.

Michael Mintz
  • 9,007
  • 6
  • 31
  • 48
Okken
  • 2,536
  • 21
  • 15
36

The docs for unittest would be a good place to start.

Also, it is a bit late now, but in the future please consider writing unit tests before or during the project itself. That way you can use them to test as you go along, and (in theory) you can use them as regression tests, to verify that your code changes have not broken any existing code. This would give you the full benefit of writing test cases :)

Justin Ethier
  • 131,333
  • 52
  • 229
  • 284
  • That's if you want test-driven development, which is not a bad thing to have. In my case, I'm looking at existing code and trying to understand it by writing and tweaking tests to pass, and that got me started on `unittest`. Once I get the hang of things, I'll be using it more for development, as well as increasing the number of test cases for each unit. – icedwater Apr 02 '15 at 08:20
  • Hi, could you please tell how can I prevent `skip()`, `skipIf()` method from escaping the reason string. The problem is the output of the `skip()` or `skipIf()` decorator is joined at \n which I don't want. Please enlighten me! – Ayush Dec 25 '21 at 08:15
27

unittest comes with the standard library, but I would recommend you nosetests.

"nose extends unittest to make testing easier."

I would also recommend you pylint

"Analyzes Python source code looking for bugs and signs of poor quality."

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ssoler
  • 4,884
  • 4
  • 32
  • 33
8

As others already replied, it's late to write unit tests, but not too late. The question is whether your code is testable or not. Indeed, it's not easy to put existing code under test, there is even a book about this: Working Effectively with Legacy Code (see key points or precursor PDF).

Now writing the unit tests or not is your call. You just need to be aware that it could be a tedious task. You might tackle this to learn unit-testing or consider writing acceptance (end-to-end) tests first, and start writing unit tests when you'll change the code or add new feature to the project.

Palimondo
  • 7,281
  • 4
  • 39
  • 58
philant
  • 34,748
  • 11
  • 69
  • 112
3

nosetests is a brilliant solution for unit testing in Python. It supports both unittest based testcases and doctests, and gets you started with it with just a simple configuration file.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Daniel Kluev
  • 11,025
  • 2
  • 36
  • 36
  • Your nosetests link is obsolete. It seems the new location is: nose.readthedocs.org/en/latest – odigity Jan 30 '13 at 18:01
  • 1
    As per the documentation on github and the nosetest website, `nose` and `nose2` are in maintanance mode. Its better to start with `py.test` as it has a lot more support – alpha_989 Jan 28 '18 at 17:35