{"id":1135,"date":"2014-08-26T06:44:46","date_gmt":"2014-08-26T10:44:46","guid":{"rendered":"http:\/\/qxf2.com\/blog\/?p=1135"},"modified":"2018-04-24T10:32:37","modified_gmt":"2018-04-24T14:32:37","slug":"python-unit-checks","status":"publish","type":"post","link":"https:\/\/qxf2.com\/blog\/python-unit-checks\/","title":{"rendered":"Python unit tests using mock"},"content":{"rendered":"<p><strong>Problem:<\/strong> Introductions to Python unit checking are too basic<\/p>\n<p>This post is for the hands on tester looking to practice their unit checking skills.<\/p>\n<hr \/>\n<h3>Why this post?<\/h3>\n<p>Unit checks are good. They play an <a href=\"http:\/\/www.mountaingoatsoftware.com\/blog\/the-forgotten-layer-of-the-test-automation-pyramid\">important role<\/a> in your regression suite. Online tutorials of Python unit checks invariably leave me wanting more. The examples covered are extremely basic. Further, these basic tutorials miss one key step in learning unit checking &#8211; the ability to read code written by somebody else. This problem ends with this post. I take an open source Python application, read through the code and put in a unit check for one method. At the end of this tutorial, you will have learnt about mocking objects and patch decorators. <strong>Bonus:<\/strong> You will have a real application to practice your unit checking.<\/p>\n<hr \/>\n<h3>Setup<\/h3>\n<p>This post will show you how to unit check a Python application using the Python <a href=\"https:\/\/docs.python.org\/2\/library\/unittest.html\">unittest<\/a> module and the Python mock module. <a href=\"http:\/\/www.qxf2.com\">Our<\/a> love affair with Python and chess continues. We will use the <a href=\"http:\/\/www.pygame.org\/project-Python+Chess-1099-.html\">Python Chess<\/a> application as the software under test and write a unit check for one of the methods. To get setup:<\/p>\n<p><strong>1. Install mock <\/strong><br \/>\nWe will use the Python <a href=\"https:\/\/pypi.python.org\/pypi\/mock\">mock<\/a> module. The mock module has one of my favorite features &#8211; <a href=\"http:\/\/www.toptal.com\/python\/an-introduction-to-mocking-in-python\">patch decorators<\/a>, that make it easy to mock classes. We are doing this on Python 2.7. For Python 3.x you could skip this step. To install mock, open a command prompt and run:<\/p>\n<pre lang=\"python\">pip install -U mock<\/pre>\n<p><strong>2. Download the Python Chess application<\/strong><br \/>\nDownload the <a href=\"http:\/\/www.pygame.org\/project-Python+Chess-1099-.html\">Python Chess app<\/a>. You may also need to download and install <a href=\"http:\/\/www.pygame.org\/download.shtml\">pygame<\/a> for your corresponding Python version. Pygame lets you run the application.<\/p>\n<hr \/>\n<h3>Write the Python unit check<\/h3>\n<p>The application we have chosen is small enough for you to look at the different classes and what they do. For this post, we are choosing to write a unit check for the <em>IsCheckmate<\/em> method in <strong>ChessRules<\/strong> class.<br \/>\n1. Get to know your application<br \/>\n2. Notice the key call<br \/>\n3. Mock and patch the method <em>GetListOfValidMoves<\/em><br \/>\n4. Design the chessboard position needed for the unit check<br \/>\n5. Create the expected argument calls<br \/>\n6. Assert that the list of calls and the arguments were correct<br \/>\n7. Put it all together<br \/>\n8. Run the Test<\/p>\n<p><strong>1. Get to know your application<\/strong><br \/>\nOpen up ChessRules.py in your favorite editor and read through the <em>IsCheckmate<\/em> method.<\/p>\n<pre lang=\"python\">def IsCheckmate(self,board,color):\r\n\t#returns true if 'color' player is in checkmate\r\n\t#Call GetListOfValidMoves for each piece of current player\r\n\t#If there aren't any valid moves for any pieces, then return true\r\n\r\n\tif color == \"black\":\r\n\t\tmyColor = 'b'\r\n\t\tenemyColor = 'w'\r\n\telse:\r\n\t\tmyColor = 'w'\r\n\t\tenemyColor = 'b'\r\n\r\n\tmyColorValidMoves = [];\r\n\tfor row in range(8):\r\n\t\tfor col in range(8):\r\n\t\t\tpiece = board[row][col]\r\n\t\t\tif myColor in piece:\r\n\t\t\t\tmyColorValidMoves.extend(self.GetListOfValidMoves(board,color,(row,col)))\r\n\r\n\tif len(myColorValidMoves) == 0:\r\n\t\treturn True\r\n\telse:\r\n\t\treturn False\r\n<\/pre>\n<p><strong>2. Notice the key call<\/strong><br \/>\nMost methods that you want to write unit checks for, will hand off some of their logic to other methods. Its important that these other methods (called methods) are mocked so that you can check the working of the method under test in isolation. When a unit check fails, its because of a specific problem with the method under test. In our example, notice that the key call in the <em>IsCheckmate<\/em> is the call to <em>GetListOfValidMoves<\/em> in the line:<\/p>\n<p><em>myColorValidMoves.extend(self.<strong>GetListOfValidMoves<\/strong>(board,color,(row,col)))<\/em>.<\/p>\n<p>We will check whether the <em>GetListOfValidMoves<\/em> method is getting called with the arguments that we expect it to be called with. The method <em>IsCheckmate<\/em> is working correctly as it is calling <em>GetListOfValidMoves<\/em> with the right arguments. Bugs in <em>GetListOfValidMoves<\/em> will be caught by unit checks written for <em>GetListOfValidMoves<\/em>. Note that for this blog post we have chosen to write one among a large number of possible unit checks for the <em>IsCheckmate<\/em> method. We chose this particular check because it illustrates multiple key concepts: mocking objects, patching methods, reading and understanding code.<\/p>\n<p><strong>3. Mock and patch the method <em>GetListOfValidMoves<\/em><\/strong><br \/>\nSince the method <em>GetListOfValidMoves<\/em> is the key call here, lets mock and patch the method. To do so, you can simply begin with these lines:<\/p>\n<pre lang=\"python\">import unittest, mock\r\n\r\n    @mock.patch('ChessRules.ChessRules.GetListOfValidMoves')        \r\n    def test_Checkmate(self, mockGetListOfValidMoves):\r\n<\/pre>\n<p>You can patch a method by calling the <strong>@mock.patch<\/strong> decorator. You can then access this patched object via the argument <strong>mockGetListOfValidMoves<\/strong>.<\/p>\n<p><strong>4. Design the chessboard position needed for the unit check<\/strong><br \/>\nFor this example, lets choose a simple chessboard position &#8211; the starting position. To create this chessboard object, you will need the following lines:<\/p>\n<pre lang=\"python\">from ChessBoard import ChessBoard\r\n        # Creating objects of Chessboard and ChessRules class and calling IsCheckmate function with each piece for initial position and \"black\" color\r\n        cb = ChessBoard(0) #Create a chess board object with the initial position\r\n<\/pre>\n<p>NOTE: ChessBoard(0) initializes the chessboard to the initial position.<\/p>\n<p><strong>5. Create the expected argument calls <\/strong><br \/>\nBy reading through the <em>IsCheckmate<\/em> method, we expect GetListOfValidMoves to be called sixteen times with every black piece on the board for the chess position we are passing it.<\/p>\n<pre lang=\"python\">        \r\n# Create expected_arg_calls list which is supposed to be called with GetListOfValidMoves for initial position\r\n# IsCheckmate calls GetListOfValidMoves with arguments: board, color (who is to play?) and co-ordinates of a square with a piece on it\r\nexpected_arg_calls = []\r\nfor row in range(0,2):\r\n\tfor col in range(0,8):\r\n\t\texpected_arg_calls.append(mock.call(cb.GetState(), 'black', (row, col)))\r\n<\/pre>\n<p><strong>6. Assert that the list of calls and the arguments were correct<\/strong><br \/>\nWe can assert that the mocked object got called with the right arguments by adding this line:<\/p>\n<pre lang=\"python\"># Assert that the mockGetListOfValidMoves.call_args_list matches expected_arg_calls\r\nself.assertEqual(mockGetListOfValidMoves.call_args_list, expected_arg_calls)\r\n<\/pre>\n<p><strong>7. Put it all together<\/strong><br \/>\nHere is the final script you need. Please place it in the same directory as where you have ChessRules.py and ChessBoard.py.<\/p>\n<pre lang=\"python\">\"\"\"\r\nExample written for Qxf2 Services' blog post on Python Unit Checking\r\nCheck if IsCheckmate method in ChessRules class calls GetListOfValidMoves  \r\nAssert that it called with the expected arguments\r\n\"\"\"\r\nimport unittest, mock\r\nimport ChessRules \r\nfrom ChessBoard import ChessBoard\r\n\r\nclass CheckIsCheckmate(unittest.TestCase):\r\n    \"Class to unit check the IsCheckmate method of ChessRules.py module\"\r\n    # creating a mock for GetListOfValidMoves\r\n    @mock.patch('ChessRules.ChessRules.GetListOfValidMoves')        \r\n    def test_Checkmate(self, mockGetListOfValidMoves):\r\n        \"Unit test for ChessRules method: IsCheckmate\"\r\n        # NOTE 1: We only check that there are valid moves for a given color\r\n        # NOTE 2: We are NOT checking the setting color logic in this unit test. You need to write another unit test for this logic.\r\n                \r\n        # Creating objects of Chessboard and ChessRules class and calling IsCheckmate function with each piece for initial position and \"black\" color\r\n        cb = ChessBoard(0) #Create a chess board object with the initial position\r\n        chess_rules_obj = ChessRules.ChessRules()\r\n        chess_rules_obj.IsCheckmate(cb.GetState(),\"black\")\r\n        \r\n        # Create expected_arg_calls list which is supposed to be called with GetListOfValidMoves for initial position\r\n        # IsCheckmate calls GetListOfValidMoves with arguments: board, color (who is to play?) and co-ordinates of a square with a piece on it\r\n        expected_arg_calls = []\r\n        for row in range(0,2):\r\n            for col in range(0,8):\r\n                expected_arg_calls.append(mock.call(cb.GetState(), 'black', (row, col)))\r\n                \r\n        # Assert that the mockGetListOfValidMoves.call_args_list matches expected_arg_calls\r\n        self.assertEqual(mockGetListOfValidMoves.call_args_list, expected_arg_calls)\r\n\r\n        # DID YOU KNOW?\r\n        # assert_any_call can be used to assert a method that was called at least once with some arguments        \r\n        #mockGetListOfValidMoves.assert_any_call(cb.GetState(),\"black\",(1,6))\r\n\r\n        # DID YOU KNOW?\r\n        # call_count can be used to check the number of times your mocked method was called\r\n        #self.assertEqual(mockGetListOfValidMoves.call_count,16)\r\n       \r\n               \r\nif __name__==\"__main__\":\r\n    unittest.main()\r\n<\/pre>\n<p><strong>8. Run the Test<\/strong><br \/>\nYay! Run the test.<\/p>\n<p><a href=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2014\/08\/RunTest.jpg\" data-rel=\"lightbox-image-0\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1145\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2014\/08\/RunTest.jpg\" alt=\"Python unit check test run\" width=\"671\" height=\"181\" srcset=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2014\/08\/RunTest.jpg 671w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2014\/08\/RunTest-300x80.jpg 300w\" sizes=\"auto, (max-width: 671px) 100vw, 671px\" \/><\/a><\/p>\n<p>And that&#8217;s it. You just ran a unit check on your Python application. <strong>Bonus:<\/strong> You now have a moderately complex application to practice your unit checking.<\/p>\n<hr \/>\n<h3>References<\/h3>\n<p>I found these references very useful:<br \/>\n1. <a href=\"http:\/\/www.toptal.com\/python\/an-introduction-to-mocking-in-python\">An excellent example of Python mock and patching<\/a><br \/>\n2. <a href=\"https:\/\/blog.isotoma.com\/2014\/05\/using-mock-patch-in-automated-unit-testing\/\">Another tutorial on getting started with mock objects<\/a><br \/>\n3. <a href=\"http:\/\/www.youtube.com\/watch?v=d3_LdLzWSXQ\" data-rel=\"lightbox-video-0\">Nice Youtube video introducing Mock<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Problem: Introductions to Python unit checking are too basic This post is for the hands on tester looking to practice their unit checking skills. Why this post? Unit checks are good. They play an important role in your regression suite. Online tutorials of Python unit checks invariably leave me wanting more. The examples covered are extremely basic. Further, these basic [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[38,64,18,66],"tags":[],"class_list":["post-1135","post","type-post","status-publish","format-standard","hentry","category-automation","category-mock","category-python","category-unit-testing"],"_links":{"self":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/1135","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/comments?post=1135"}],"version-history":[{"count":40,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/1135\/revisions"}],"predecessor-version":[{"id":1246,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/1135\/revisions\/1246"}],"wp:attachment":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/media?parent=1135"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/categories?post=1135"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/tags?post=1135"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}