{"id":5739,"date":"2017-12-31T20:10:21","date_gmt":"2017-12-31T20:10:21","guid":{"rendered":"http:\/\/putridparrot.com\/blog\/?p=5739"},"modified":"2017-12-31T20:10:21","modified_gmt":"2017-12-31T20:10:21","slug":"unit-testing-in-python","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/unit-testing-in-python\/","title":{"rendered":"Unit testing in Python"},"content":{"rendered":"<p>As Python is a dynamic language, unit testing is not only important for verifying code works as expected, but also needs to cover situations that statically typed languages get for free. So a high level of test coverage is useful to ensure event basic methods are working and even named as expected.<\/p>\n<p>Let&#8217;s create a simply Calculator class which we will then write unit tests for (this is saved in a file named calc.py)<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\nclass Calculator:\r\n    def add(self, a, b):\r\n        return a + b\r\n<\/pre>\n<p>We can then create a file test_calculator.py and within this we have the following<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\nfrom unittest import TestCase\r\nfrom calc import Calculator\r\n\r\n\r\nclass TestCalculator(TestCase):\r\n    def test_add(self):\r\n        c = Calculator()\r\n        self.assertEqual(5, c.add(3, 2))\r\n<\/pre>\n<p>As you can see, we need to derive our test class from the TestCase class and test methods should use the naming convention <em>test_<\/em> at the start of the test method&#8217;s name.<\/p>\n<p><em>Note: the class name does not require the Test prefix\/naming convention.<\/em><\/p>\n<p>Using PyCharm we need to create a new configuration, from the Python tests configuration section. Select nosetests and then name the configuration, something like Calculator Tests.<\/p>\n<p>Now we can run the tests. If you find nosetest is not installed you can run the Python Console from PyCharm and run the command<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\npip install nose\r\n<\/pre>\n<p><strong>setUp\/tearDown<\/strong><\/p>\n<p>Like most unit testing frameworks, the TestCase class can use a setUp and\/or tearDown method for setting up the test case context and cleaning up after each test method is run.<\/p>\n<p>For example<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\nclass CalculatorTests(TestCase):\r\n\r\n    def setUp(self):\r\n        self.c = Calculator()\r\n\r\n    def test_add(self):\r\n        self.assertEqual(5, self.c.add(3, 2))\r\n\r\n    def test_subtract(self):\r\n        self.assertEqual(2, self.c.subtract(7, 5))\r\n<\/pre>\n<p><strong>setUpClass\/tearDownClass<\/strong><\/p>\n<p>TestCase also includes setUpClass and tearDownClass for setting context for all test methods within a TestCase.<\/p>\n<p>For example, here&#8217;s the previous TestCase but using the setUpClass to create the calculator for all test methods<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\nclass CalculatorTests(TestCase):\r\n\r\n    @classmethod\r\n    def setUpClass(cls):\r\n        cls.c = Calculator()\r\n\r\n    def test_add(self):\r\n        self.assertEqual(5, self.c.add(3, 2))\r\n\r\n    def test_subtract(self):\r\n        self.assertEqual(2, self.c.subtract(7, 5))\r\n<\/pre>\n<p><em>Note: the @classmethod is required in this example code or the setUpClass is not treated as a class method as is expected.<\/em><\/p>\n<p><strong>References<\/strong><\/p>\n<p><a href=\"https:\/\/docs.python.org\/2\/library\/unittest.html\" rel=\"noopener\" target=\"_blank\">unittest \u2014 Unit testing framework<\/a><br \/>\n<a href=\"https:\/\/confluence.jetbrains.com\/display\/PYH\/Creating+and+running+a+Python+unit+test\" rel=\"noopener\" target=\"_blank\">Creating and running a Python unit test<\/a> <\/p>\n","protected":false},"excerpt":{"rendered":"<p>As Python is a dynamic language, unit testing is not only important for verifying code works as expected, but also needs to cover situations that statically typed languages get for free. So a high level of test coverage is useful to ensure event basic methods are working and even named as expected. Let&#8217;s create a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[195],"tags":[],"class_list":["post-5739","post","type-post","status-publish","format-standard","hentry","category-python"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/5739","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=5739"}],"version-history":[{"count":6,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/5739\/revisions"}],"predecessor-version":[{"id":5745,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/5739\/revisions\/5745"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=5739"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=5739"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=5739"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}