On Tue, Apr 01, 2014 at 12:30:46PM +0100, Sydney Shall wrote: > Another debutant! > I am having trouble learning to use unittests. > My question is; > In the example below, did you write the class > "SquareRootTests(unittest.TestCase):" ?
Yes, that unit test was written by Danny (I assume -- I suppose he might have copied it from somewhere else.) > Or do I find a set of them in the library? There are a HUGE number of unit tests that come supplied with Python's source code, but they are used for testing Python itself. If your Python installation includes a "test" subdirectory, you can see the tests in there. They aren't reusable in your own code, except to read them and learn from them. Instead, you write your own tests, to suit your own code, using the unittest module to do all the heavy-lifting. > And what is the significance of the name chosen > "self.assertAlmostEqual(square_root(3), 2.0) "? > I take it the first argument is calling my function with its argument > and the second argument is the correct answer? Correct. This "assertAlmostEqual" test takes two numbers: - first Python calls your square_root function with 3, and gets some number which hopefully will be around 1.732; - then Python takes the number 2.0; - finally it calls the "assertAlmostEqual" test, which tests whether or not 1.732 is "almost equal" to 2.0, according to whatever scheme it uses to compare two numbers. (They don't.) If they compared "almost equal", then that specific test would have counted as a passing test. But since they don't, then it counts as a test failure. The idea is that you collect all the test failures, and they represent bugs in your code that should be fixed. Although they might be a bug in the test! In this case, Danny intends that as a deliberately buggy test -- 1.732... is *not* "approximately equal" to 2, at least not according to the rules of unittest. > I am quite unclear how one proceeds to set up unittests. Fortunately, most of the hard work is done for you by the unittest module. Suppose you have a simple module with one function and you want to test it: # module pizza.py def make_pizzas(number): return "made %d pizzas" % number That's pretty simple, right? So simple that you can almost look at it and see that it works correctly. make_pizza(5) => returns "made 5 pizzas" But let's do some nice simple unit tests for it. Start with a new file, which I would call "test_pizza.py", and import two modules: unittest, and your own module. (You need to import your module, so Python knows what you are testing.) # test_pizza.py import pizza import unittest The unittest module has a *lot* of complex code in it, because it has a lot of work that it needs to do. It needs to find the tests, initialise them, run the tests, collect the results, display a visual indication of whether tests are passing or failing, and so on. But to make this work, all we need do is write the tests in a way that the unittest module understands. We do that by using inheritance: we inherit from the TestCase class: class MakePizzaTests(unittest.TestCase): """Collect all the tests for the make_pizza function.""" It's good practice to have a separate class for each group of related tests. In this case, because there's only one function, we can put all the tests for that function into one class. If there was a second function, we would use a second class: class MakeSaladTests(unittest.TestCase): ... but there isn't, so we won't. At the moment, if we run the tests in this, there will be zero tests run and zero failed. Because we haven't actually written any tests, just the beginnings of it! So let's add a simple test. What's the simplest thing we can think of about the make_pizza function? It returns a string! So let's test it: class MakePizzaTests(unittest.TestCase): """Collect all the tests for the make_pizza function.""" def test_make_pizza_returns_string(self): # Test that make_pizza returns a string. for num in (1, 2, 3, 100, 1000, 78901): result = pizza.make_pizza(num) self.assertIsInstance(result, str) Here, we don't actually case what result make_pizza gives us, we just want to check that it returns a string. Any old string will do. It's good practice to start with more general tests, then work your way down to writing specific tests. Notice that this test tries the function with half a dozen different values. If I tried it with only one value, say 23, and the test passed, maybe the code only passes with 23 but fails with everything else. In a perfect world, I could try testing with *every* possible value, but that might take a while, a long, long while, so I compromise by testing with just a handful of representative values. Now, let's test this out. At your shell prompt (not the Python interactive interpreter!), run this command from inside the same directory as your pizza.py and test_pizza.py files: python3.3 -m unittest test_pizza Notice that I *don't* include the .py after test_pizza. Unittest needs to import it as a module. If you do this, unittest will run the one test it finds, print a single dot, and you're done. Success! Our first test passed. Let's add a few more: edit the test_pizza file and add these two methods to the MakePizzaTests class: def test_make_pizzas(self): # Test that make_pizza returns the expected result. self.assertEqual(pizza.make_pizza(7), "made 7 pizzas") self.assertEqual(pizza.make_pizza(23), "made 23 pizzas") def test_make_1_pizza(self): # Test that make_pizza gives us a special result with 1 pizza. result = pizza.make_pizza(1) self.assertEqual(result, "made 1 pizza") This time, if you run the tests, you'll get two dots and an F for Fail. The test_make_1_pizza fails. Can you see why, and how to fix the bug in the make_pizza function? -- Steven _______________________________________________ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor