DEVASC Python – Error Handling in Python, Test Driven Development (TDD), and Unit Testing reviewed!

This will be the finishing “Python” focused article, and I will keep it brief!

Above is a jump all the way to the bottom of this post for “Unit Testing” which will be gotten to quick, but I kind of stumbled around trying to understand how to do it from Bash Shell, but eventually just ended up using Visual Studio Code to get the code correct!

This will be a shorter one to finish Python stuff, so lets get to it! πŸ˜€

Error Handling in Python

This is somehow brand new to me or I skimmed it over, the “try-except-else-finally” code block that doesn’t just error out a program, but gives the user chances to correct course before the program finally exits.

I am going to steal the code right out of the DevNet OCG to test this out, and see if I can write my own code once I get a feel for the flow of the script / operations, here we go:

This logic is amazing, I didn’t realize you could use the += operator to increment an integer per iteration, so lets go through all this step be step through the script before running:

  1. x = 0 – This is the starting point for the threshold of failed attempts
  2. while True: – This begins a boolean “while” Loop with tons of nested statements
  3. try: – Beings a try-except-else-finally error handling statement
  4. filename = input(“Input something”) – User inputs the filename they are trying to open
  5. “with” statement will open the filename based upon the input from user
  6. file_data variable is defined to read / output file data if entered correctly down script
  7. except FileNotFoundError: – Python detects an error of the file not being found
  8. Prints out a message saying the file wasn’t found, try again message
  9. If file name error is not detected, skips to else:, prints file data and exits program
  10. x = 0 resets the counter until it hit the exit program threshold of tries
  11. break – Exits program / While loop
  12. finally: – This line is hit if Filename Error occurs, increments x, if x = 3 game over
  13. If x == 3, triggers final lines to exit while loop / program
  14. prints two lines advising the program is exiting, try again
  15. Break exits the while loop / program

So this is actually a “while” loop with a nested error-handling statement that iterates while incrementing the variable, until the file successfully opens or the threshold exits program.

The irony that failing opening the file makes the program succeed is not lost on me!

Python don’t pity this foo, my program works, and I can open the correct file!

However – There is a catch I didn’t get right away with this error handling technique as I tried to enter the actual file name somewhere, which opened it no matter what was typed.

With some playing around, I found ALL filename variables need to be generic ‘filename’ :

I tried this initially and it didn’t work, however in working with GIT, my VSC (and myself) hardly know which repository I am putting files in, and the correct file needs to be in the same folder / GIT Repo so when its name is entered it has a $PATH to retrieve it.

I will be doing some playing around with error handling at a later time, but for further review or examples of error handling, visit https://docs.python.org/3/tutorials/errors

Test-Driven Deployment (TDD)

This type of deployment at first sounds like building a crash test dummy / brick wall before building the car to crash into it to test for safety features, but when you think of creating the test before the product, you are creating a standard of quality the code must be built to meet.

Using that analogy you will be crashing a lot more cars this way (or chasing bugs in code), and continue to build cards / create code to test against the test until it passes, moving away from the analogy you will spend a good portion of front end time creating the test and chasing / correcting bugs in your code until it passes the test.

Though it seems backward intuitive, its really defining the functionality of your code before even beginning to spend your time coding, so once you get to work the code can be quickly tested / updated / tested until it passes the code test – This is done in 5 steps:

TDD: Write Test -> Test Fails -> Write Code -> Test Passes -> Refactor

  1. Write Test – Write the test that fits your goal for new features like classes or functions to be added to the code, define the naming conventions of the new class or functions to be added, and do not test for anything outside of exactly what is desired
  2. Test Fails – You run existing code against the test and it fails, and the errors indicate what needs to be changed / added / etc to help guide coding the feature intended to pass
  3. Write Code – Write only the code for the new feature of classes or functions that will allow the code to pass the designed test, this is purely geared towards focus and efficiency
  4. Test Passes – The code passes the test and can move onto final phase
  5. Refactor – Code cleanup, removing hard coded variables used for testing, remove any clutter from the script to keep it ‘clean code’ and make any improvements needed

It really could not seem much more backwards intuitive as this is the opposite of the “measure twice, cut once” mindset I’ve grown up, though with code its efficient because it doesn’t make sense to make code for a goal / produce a test / fail the test / update the code / test / etc – All of that is wasted time that could have been clearly defined immediately.

Unit Testing

Testing Software and the Code that makes it run is not optional, it has to be done.

The idea of “Unit Testing” is why test an entire script of code, when you have not verified what might happen if unexpected input is sent into a function, like the error handler program I demonstrated above?

That is actually a bad example, this a good example of why Unit Testing is a must:

Lets say this is part of your Tax Form for a year, and this one tiny piece of code will generate your Payroll Taxes out of ALL Taxes owed in the Software, but you cannot divide a String Literal by an Integer and you can’t just re-word it to clarify it needs a decimal value.

That error handling could come in handy if we re-worded it with tax language and integrated this code into it just to make this semi-functional, but semi-functional Software / Code is not what Developers deploy as finished products to their customers if they want to keep their business / jobs for very long.

Unit Tests are the first Tests performed, followed by Integration Tests to ensure it integrates into the Software Code, and finally Functional Tests on the Software Itself.

For the purpose of testing our code, Python has the “unittest” module to the rescue!

This module is definitely worth an “import unittest” and “help(unittest)” as its help page is MASSIVE and incredibly descriptive, and also links to further test features in Python.

It funny how you write a piece of code to make it fail, and the only way you can get it to stumble is to make a typo by not closing your ‘r’ variable πŸ™‚ Oooh Python, you rascal!

“unittest” Module comes with a robust amount of tests that include the names “Nose” and “PyTest” that may be useful for exam day, but mainly I believe you will only need to know how the unittest module works in general for DEVASC.

While these robust tests can basically test your code inside out, its best practice to use certain conventions of OOP like matching the tests being run focused on your code, and also the name of your test should match what you are trying to accomplish.

One thing that surprised me about “unittest” is that its actually run from Bash!

This file will be “test_areacircle.py” in my Bash Directory that will perform the unittest:

The top portion is the portion that will run different parameters against the “area_of_circle.py” script, and the bottom two lines from my understanding will run ALL Python scripts against this Unit Test file, so I am interested to see how this works.

To verify we are ready to rock I “cat” both test and to be tested files from Bash prompt:

I’m in completely uncharted territory here, lets execute the unittest and see what happens:

Well. It worked. Kind of. This is the first time its actually even began to run, I’ve had to clean up syntax goof ups and just add “import (something” to each script to make sure they are locked and loaded – I feel like I am on a unicycle in a clown suit juggling Python scripts πŸ™‚

I don’t get why I see Python Errors mentioned as “cryptic” in so much training material, as they generally could not really be more clear, as this shows us it is hitting that bottom line where __main__ resides however it does not know what “area_of_circle” is.

This time I am going to try switching up where certain objects exist in the scripts:

I didn’t think about it, but I realized I could put both files into GIT, and use VSC:

Now for an example of what a Unit Test Looks like when it fails, and how to decipher it:

I added the lines 12-14 in VSC to create a second function in the Unit Test with a value of -1 at the end, which causes it to fail, as the Radius of -1 is not a possible math value.

I wanted to point out the big fat “.F” at the top of the fail message output along with at the bottom “FAILED (failures=1)”, and also the error line that shows both the exact line of code that caused the test to fail and a brief explanation of why it failed below that line.

To fix this you can adjust the testme.py file to embed a little if statement within the file:

Then to run the same unit test against the newly added if statement in the test script:

That would also be considered “Error Handling” in unit testing by using the “if” statement in the unit test, you can also use if / elif / loops within unit testing and there is a great site I found that has a ton of “unittest” examples and best practices:

https://code.tutsplus.com/tutorials/write-professional-unit-tests-in-python–cms-25835

Some best practices for DEVASC exam day off the top of my head:

  • “Unit”s are the smallest code unit for a piece of software that can be tested
  • Multiple test scripts can be made for different purposes as needed
  • Test names should be intuitive to their exact function they test
  • Tests should be as defined as possible to test your exact requirements

I would also check out that link, I sure am going to myself, but I can’t add any of that content here as much as I’d like to plagiarize that great article, definitely worth a read!

That is it for Python (I think) for a little bit! Next up is a look at Meraki API!

Next up in my DevNet OCG is API’s which I am stoked for, but I’ve been craving hitting the Meraki material on my home stack to see what I can break after Python, and I am now done with Python so next up I am calling a “Meraki Audible” in studies before API specifics!

Until next time!!! πŸ™‚

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s