ABOUT ME

Today
Yesterday
Total
  • Python - unittest Framework
    python 2022. 8. 8. 09:59
    • Python's unittest module provides us with a test runner.
      • A test runner is a component that collects and executes tests and then provides results to the user.
      • The framework also provides many other tools for test grouping, setup, teardown, skipping, and other features that we’ll soon learn about.
    • The assertEqual() method takes two values as arguments and checks that they are equal. If they are not, the test fails.
      • self.assertEqual(value1, value2)
    • The assertIn() method takes two arguments. It checks that the first argument is found in the second argument, which should be a container. If it is not found in the container, the test fails.
      • self.assertIn(value, container)
    • The assertTrue() method takes a single argument and checks that the argument evaluates to True. If it does not evaluate to True, the test fails.
      • self.assertTrue(value)
    • The assertAlmostEqual()  method method takes two arguments and checks that their difference, when rounded to 7 decimal places, is 0. If the values are not close enough to equality, the test will fail.
      • self.assertAlmostEqual(value1, value2)
    • The assertLess() method takes two arguments and checks that the first argument is less than the second one. If it is not, the test will fail.
      • self.assertLess(value1, value2)
    • The assertRaises() method takes an exception type as its first argument, a function reference as its second, and an arbitrary number of arguments as the rest.
      • self.assertRaises(specificException, function, functionArguments...)
    self.assertEqual(2, 5) assert 2 == 5
    self.assertIn(5, [1, 2, 3]) assert 5 in [1, 2, 3]
    self.assertTrue(0) assert bool(0) is True
    self.assertLess(2, 5) assert 2 < 5
    self.assertAlmostEqual(.22, .225)
    assert round(.22 - .225, 7) == 0
    import unittest
    
    def get_daily_movie():
        print('Retrieving the movie set to play on today\'s flight...')
        return 'Parasite'
    
    def get_licensed_movies():
        print('Retrieving the list of licenses movies from the database...')
        licensed_movies = ['Parasite', 'Nomadland', 'Roma']
        return licensed_movies
    
    def get_wifi_status():
        print('Checking WiFi signal...')
        print('WiFi is active')
        return True
    
    def get_device_temp():
        print('Reading the temperature of the entertainment system device...')
        return 40
    
    def get_maximum_display_brightness():
        print('Calculating maximum display brightness in nits...')
        return 399.99999999
        
    class EntertainmentSystemTests(unittest.TestCase):
    
      def test_movie_license(self):
        daily_movie = get_daily_movie()
        licensed_movies = get_licensed_movies()
        self.assertIn(daily_movie, licensed_movies)
    
      def test_wifi_status(self):
        wifi_enabled = get_wifi_status()
        self.assertTrue(wifi_enabled)
    
      def test_maximum_display_brightness(self):
        brightness = get_maximum_display_brightness()
        self.assertAlmostEqual(brightness, 400)
    
      def test_device_temperature(self):
        device_temp = get_device_temp()
        self.assertLess(device_temp, 35)
    
    unittest.main()

    • By parameterizing tests, we can leverage the functionality of a single test to get a large amount of coverage of different inputs.
    import unittest
    import entertainment
    
    class EntertainmentSystemTests(unittest.TestCase):
    
      def test_movie_license(self):
        daily_movies = entertainment.get_daily_movies()
        licensed_movies = entertainment.get_licensed_movies()
    
        for movie in daily_movies:
          with self.subTest(movie):
            self.assertIn(movie, licensed_movies)
    
    unittest.main()

    • One of the most important principles of testing is that tests need to occur in a known state.
      • If the conditions in which a test runs are not controlled, then our results could contain false negatives (invalid failed results) or false positives (invalid passed results).
    • A test fixture is a mechanism for ensuring proper test setup (putting tests into a known state) and test teardown (restoring the state prior to the test running).
      • Test fixtures guarantee that our tests are running in predictable conditions, and thus the results are reliable.
      • The methods setUp(self) & tearDown(self) define the conditions that will run for each test iteration within the class
      • The methods setUpClass(cls) & tearDownClass(cls)
      • Controlling your test setup will greatly save time and resources depending on your test's objective.
    • In the example below, the two test setups differ in that the first test setup requires the power to be turned on/off every for each test, while the second test setup tests all test cases before turning the power off.

     

    def power_cycle_device():
      print('Power cycling bluetooth device...')
     
    class BluetoothDeviceTests(unittest.TestCase):
      def setUp(self):
        power_cycle_device()
     
      def test_feature_a(self):
        print('Testing Feature A')
     
      def test_feature_b(self):
        print('Testing Feature B')
     
      def tearDown(self):
        power_cycle_device()
        
    Output:
        Power cycling bluetooth device...
        Testing Feature A
        Power cycling bluetooth device...
        Power cycling bluetooth device...
        Testing Feature B
        Power cycling bluetooth device...
        .
        ----------------------------------------------------------------------
        Ran 2 tests in 0.000s
    
        OK
    
    def power_cycle_device():
        print('Power cycling bluetooth device...')
     
    class BluetoothDeviceTests(unittest.TestCase):
      @classmethod
      def setUpClass(cls):
        power_cycle_device()
     
      def test_feature_a(self):
        print('Testing Feature A')
     
      def test_feature_b(self):
        print('Testing Feature B')
     
      @classmethod
      def tearDownClass(cls):
        power_cycle_device()
    
    
    Output:
    	Power cycling bluetooth device...
        Testing Feature A
        Testing Feature B
        Power cycling bluetooth device...
    
        ----------------------------------------------------------------------
        Ran 2 tests in 0.000s
    
        OK

    Sometimes we have tests that should only run in a particular context. For example, we might have a group of tests that only runs on the Windows operating system but not Linux or macOS. For these situations, it’s helpful to be able to skip tests.


    • Sometimes we have tests that should only run in a particular context.
      • For example, we might have a group of tests that only runs on the Linux operating system but not Windows or macOS. For these situations, it’s helpful to be able to skip tests.
      •  The unittest framework provides two different ways to skip tests.
        • The @unittest skip decorator
        • The skipTest() method

     

    import sys
     
    class LinuxTests(unittest.TestCase):
     
        @unittest.skipUnless(sys.platform.startswith("linux"), "This test only runs on Linux")
        def test_linux_feature(self):
            print("This test should only run on Linux")
     
        @unittest.skipIf(not sys.platform.startswith("linux"), "This test only runs on Linux")
        def test_other_linux_feature(self):
            print("This test should only run on Linux")

    • Sometimes we have a test that we know will fail.
      • This could happen when a feature has a known bug or is designed to fail on purpose.
    • In this case, we wouldn’t want an expected failure to cloud our test results.
    • Rather than simply skipping the test, unittest provides a way to mark tests as expected failures.
    • Expected failures are counted as passed in our test results.
      • If the test passes when we expected it to fail, then it is marked as failed in test results.

    'python' 카테고리의 다른 글

    Python - Pandas Fundamentals Revisited  (0) 2022.08.26
Designed by Tistory.