/ 写在前面 – 我热爱技术、热爱开源。我也相信开源能使技术变得更好、共享能使知识传播得更远。但是开源并不意味着某些商业机构/个人可以为了自身的利益而一味地索取,甚至直接剽窃大家曾为之辛勤付出的知识成果,所以本文未经允许,不得转载,谢谢/


We can test our code using tools in Python’s unittest module.

Testing a Function

Say that we have a function that returns a neatly formatted name:

  1. # name_function.py
  2. def get_formatted_name(f_name, l_name):
  3. """Generate a neatly formatted full name."""
  4. full_name = f_name + ' ' + l_name
  5. return(full_name.title())

Then we write a test case for this function:

  1. # test_name_function.py
  2. import unittest
  3. from name_function import get_formatted_name
  4. class NameTestCase(unittest.TestCase):
  5. """Tests for 'name_function.py'."""
  6. def test_first_last_name(self):
  7. """Do names like 'Senchun Yao' work?"""
  8. formatted_name = get_formatted_name('senchun', 'yao')
  9. self.assertEqual(formatted_name, 'Senchun Yao')
  10. unittest.main()
  11. '''
  12. output:
  13. .
  14. ----------------------------------------------------------------------
  15. Ran 1 test in 0.000s
  16. OK
  17. '''

Several things need noticing:

  • At line 1, Python test file naming convention: When you run pytest , by default it will look for tests in all directories and files below the current directory. File names should start or end with “test”, as in test_example.py or example_test.py . If tests are defined as methods on a class, the class name should start with “Test”, as in TestExample . The class should not have an __init__ method. For more details, visit Naming conventions and test discoveryArchived.
  • At line 2, we import unittest module.
  • At line 3, we import a function we want to test.
  • At line 5, we create a new test class that must inherit from unittest.TestCase with name related to that function and including word test. This class will contain a series of unit tests for get_formatted_name() .
  • At line 8, The method name must start with test_ so the method runs automatically when we run test_name_function.py .
  • At line 11, we use one of unittest’s most useful features: an assert method. .assertEqual(formatted_name, 'Senchun Yao') says, “Compare the value in formatted_name to the string 'Senchun Yao' . If they are equal as expected, fine. But if they don’t match, let me know!”
  • At line 13, unittest.main() tells Python to run the tests in this file.
  • At line 17, The dot . on the first line of output tells us that a single test passed.
  • At line 21, The final OK tells us that all unit tests in the test case passed.

Testing a Class

Below are 6 commonly used assert methods:

  • assertEqual(a, b) : Verify that a == b .
  • assertNotEqual(a, b) : Verify that a != b .
  • assertTrue(x) : Verify that x is True .
  • assertFalse(x) :Verify that x is False .
  • assertIn(item, list) : Verify that item is in list .
  • assertNotIn(item, list) : Verify that item is not in list .

Say that we have one class named AnonymousSurvey in anonymous_survey.py:

  1. class AnonymousSurvey():
  2. def __init__(self, question):
  3. self.question = question
  4. self.responses = []
  5. def print_question(self):
  6. print(self.question)
  7. return None
  8. def store_response(self, response):
  9. self.responses.append(response)
  10. return None
  11. def print_survey_results(self):
  12. print("Here are survey results: ")
  13. for res in self.responses:
  14. print(" * " + res)

A Python file that conducts anonymous survey:

  1. # make_survey.py
  2. import anonymous_survey as a_s
  3. question = "What's your favorite movie?"
  4. survey_1 = a_s.AnonymousSurvey(question)
  5. survey_1.print_question()
  6. while True:
  7. rsp = input("Enter 'q' to quit: ")
  8. if rsp == 'q':
  9. break
  10. survey_1.store_response(rsp)
  11. survey_1.print_survey_results()

As a matter of fact, the basis of testing a class is similar to that of testing a function. Hence we get:

  1. import unittest
  2. from anonymous_survey import AnonymousSurvey
  3. class TestAnonymousSurvey(unittest.TestCase):
  4. def test_store_one_response(self):
  5. question = "What's your favorite movie?"
  6. a_sur = AnonymousSurvey(question)
  7. a_sur.store_response("Pulp Fiction")
  8. self.assertIn("Pulp Fiction", a_sur.responses)
  9. unittest.main()
  10. '''
  11. output:
  12. .
  13. ----------------------------------------------------------------------
  14. Ran 1 test in 0.000s
  15. OK
  16. '''

However, creating a new AnonymousSurvey object in every test method seems to be repetitive and daunting. So here comes the setUp() method that allows you to create these objects once and then use them in each of your test methods.

When you include a setUp() method in a TestCase class, Python runs the setUp() method before running each method starting with test_ . Any objects created in the setUp() method are then available in each test method you write.

Another version using setUp() :

  1. import unittest
  2. from anonymous_survey import AnonymousSurvey
  3. class TestAnonymousSurvey(unittest.TestCase):
  4. def setUp(self):
  5. question = "What's your favorite movie?"
  6. self.survey = AnonymousSurvey(question)
  7. self.responses = ["Pulp Fiction", "1900"]
  8. def test_store_one_response(self):
  9. self.survey.store_response(self.responses[0])
  10. self.assertIn(self.responses[0], self.survey.responses)
  11. def test_store_two_responses(self):
  12. for r in self.responses:
  13. self.survey.store_response(r)
  14. for r in self.responses:
  15. self.assertIn(r, self.survey.responses)
  16. unittest.main()
  17. '''
  18. output:
  19. ..
  20. ----------------------------------------------------------------------
  21. Ran 2 tests in 0.000s
  22. OK
  23. '''

Note: At line 9, 10, setUp() method does two things: it creates a survey instance, and it creates a list of responses. Each of these is prefixed by self. , so they can be used anywhere in the class.

Note: When a test case is running, Python prints one character for each unit test as it is completed. A passing test prints a dot . , a test that results in an error prints an E , and a test that results in a failed assertion prints an F . This is why you’ll see a different number of dots and characters on the first line of output when you run your test cases. If a test case takes a long time to run because it contains many unit tests, you can watch these results to get a sense of how many tests are passing.