Debugging, Refactoring and Unit Test

by Kardi Teknomo

In this tutorial, you will learn about debugging in Spyder. You will also about refactoring your Python code and creating your unit test.

Catching Errors

Error in programming code is very common. There are many type of common errors.

One simple way to catch the error and do something if such error happen is to use

try:

run these statements until it catch an error

except:

run these statements when there is exception error

else:

run these statements when there is no exception error in try clause

finally:

always run these statements regardless you have error or not

When we use try-catch statement, the error can still be printed but the program will not be halted. However, we will not know which line number on the try statement cause the error. During debugging, you can add raise statement in the exception clause to show the error and halt teh program.

Debugging

What is debugging?

The process of finding where and why error happens in your code is called debugging.

How do we debug?

printing the value

The simplest way to debug without any IDE is to temporarily print the value of variables or return value of function. This simplest technique require you to run the code until it found error. Then you would rely on the compiler message and the printed value to guess what is the error. Debugging can be very frustrating experience for new coders. You can code in a few minutes but debugging might takes many hours and even days. In fact, we can check if a programmer is experience or not by checking their time in debugging, not in coding. The more experience programmer would take less time in debugging.

When the compiler still give you the error message, you should be happy because computer can help you to find the error. Sometimes, your program run smoothly without error but it produces wrong results than what you expect. This kind of logical error is much harder to debug.

using debugger in IDE (Spyder)

Using IDE like Spyder, debugging can be much easier. Simply by setting breakpoint before the error happen, you would still run the code step by step while viewing the values of all variables such that you would know where and why the error happens.

When you see some error in your code, it usually show the module name and the line number.

  1. Set breakpoint in the same module, at line number right before the error happen. In Spyder, you can do this through menu Debug > Set/Clear Breakpoint (F12). You will see red code beside the line number if you have set the breakpoint
  2. Run the debugger. In Spyder, you go to menu Debug > Debug (CTRL+F5)
  3. You can use either one of the following:
    • Step (menu Debug > Step (CTRL+F10)) to run one step at a time of the line code
    • Step In (menu Debug > Step Into (CTRL+F11)) to inside another method or another module
    • Step Out (menu Debug > Step Return (CTRL+SHIFT+F11)) to go out from this method and return the caller
    • Continue (menu Debug > Continue (CTRL+F12)) to go to the next breakpoint
    • Stop (menu Debug > Stop (CTRL+SHIFT+F12)) to stop debugging You can also see the value of variables in Variable Explorer tab while you debug.

Refactoring

What is refactoring?

Refactoring is modifying your code without changing its input and output. The observable external behavior of your code after refactoring would be exactly the same but the internal behavior is improved.

Why do we refactor?

What do we change to refactor?

What is the requirement for refactoring?

You can only refactor if you have the unit test ready. The existence of unit test is the guarantee that the code would behave the same way externally (input and output).

How do we refactor?

  1. First, you need to run all of the unit tests and pass all tests without error. You can add unit tests if necessary.
  2. Then, you refactor to increase understanding of your code
  3. After that, you run again the unit test.
  4. Next, you add more unit test for the changes and modify the main code if necessary until it passes all tests.
  5. Then, you refactor the code until it would be simplest state
  6. Run the unit tests

Test Driven Development

The idea of Test-Driven Development is to create the test before you develop your code. After you finish creating the test code, then you start to create the function or the class just to pass the test. Using this simple Agile technique, you keep improving your test cases and refactor your code to pass the test.

The protocol is to do unit test before you code and after you code, the code must pass all the test. Using that protocol, you can modify or refactor your code mercilessly. Then you do the automatic testing. If the refactoring break the code, you know at least it was working before you refactor.

Test-Driven Development is very useful technique especially if you work in a team of developers. Each developer must do the protocol above. Whoever breaks the code must be responsible to fix it. Or else, his/her code would be rejected to be included in the committed code.

Unit Test

Unit test is useful to test your function or your class.

Why do we need unit test?

  1. To do refactoring (modifying the code without changing its external behavior)
  2. To do debugging
  3. To add feature
  4. To review the code

Unit test is the requirement for refactoring, debugging and adding features in your code. By spending a little more time to define your unit tests, you would save a lot of time of debugging unnecessary error caused by modifying your code that already work earlier.

How do we make unit test?

To create a unit test in Python is easy.

  1. import unittest
  2. Create a class of test cases inherited from unittest.TestCase
  3. Build test cases of the correct values inherited from unittest
  4. Build test cases of the incorrect values inherited from unittest
  5. Build the actual code (the function or the class that you want to test)
  6. Run the unit test by calling the test class using unittest.main()

To give you more concrete example, let us say we want to create a function to compute a factorial of an integer number n, that is the product of 1 2 .... * n.

References

last update: April 2021

Cite this tutorial as: Teknomo, K. (2021) Debugging, Refactoring and Unit Test using Python (http://people.revoledu.com/kardi/tutorial/Python/)

See Also:

Visit www.Revoledu.com for more tutorials in Data Science

Copyright © 2021 Kardi Teknomo

Permission is granted to share this notebook as long as the copyright notice is intact.