Keep Calm and Add Unit Tests with Python

“I just can’t figure out why my program doesn’t work. Can someone help me?”

“I’ve been working on this for hours and I’m still stuck.”

“I had it working a few minutes ago, but I did something and now nothing works!”

Making Your Own Private Hell

You probably mastered a few basics, like writing a simple Python program. You’ve gained confidence that you can write a loop or a function. You can see how a basic Python program works. You are hungry for more.

Maybe you are plowing through a book or a course on Python. Maybe it’s a class you’re taking. Or maybe you are getting ambitious and you decide to create something new, like a Reddit bot.

You are busy adding working code. You test every now and then by running the program. If there’s a problem, you edit the file and run the program again. Everything seems so easy.

Then you realize something is wrong. That part you tested 10 minutes ago, by hand, but didn’t test until just now… it’s not working. Are you just imagining this? No, you try it again. It’s still wrong. It’s still broken. If you run the program 10 more times, magic will happen and it will work. Right?

Again and again you try to fix the problem, but it only ends up somehow worse than before. Minutes turn into hours. Time is slipping by. You are so frustrated you are ready to hurl your computer out the nearest window. Why did you think you could do this programming thing anyway? It’s impossible! Only computer geniuses could keep all this straight. And this is just a basic program!

“Is it too late to get my money back?”, you think.

The Way Out

What if you could avoid all of this misery? Imagine if you could use Python itself to check if your new program was correct every time you made a change? As soon as you made any change, you could check to see if you made a mistake. You could find out right away if the change you just made made things better or worse?

Think about this: if you can check your program after every change, and you keep the changes small, then you only have to undo a small change to get back on track. This would keep you from wasting your time with big changes that will derail you for hours or days.

You should write automated software tests. When I say “automated” I mean tests you don’t have to keep in your meat brain. You just have to remember to run a single command to run every test instead of remembering to run a program multiple times to check every situation.

There’s another important benefit to these tests – it’s a professional habit. Writing tests differentiates the pros from the slobs. Writing tests for your program is like basic sanitation for doctors. Would you trust a doctor to perform surgery without washing their hands first?

Writing Tests – A Detailed Example

In this example, we already have a Python source file called rational.py.

For now, I just want you to get comfortable with the tools of creating and then running your first real tests. That’s what you’ll learn today.

You’ll get the most out of this example by following along and running the examples. The original program is located here. If you are familiar with git, you can clone the repository. Otherwise you can just copy the source code locally.

First let’s look at files in the original project.

The rational.py is the implementation and rationaltest.py is a test driver.

The test driver in this project is a “poor man’s” test framework. It’s functional, sure. If you run the file you’ll get a result like this:

We’re going to use the rationaltest.py to make our first tests easy to write. You only have to concern yourself with how to construct the tests using a testing framework. We’ll use pytest for this example.

Let’s run pytest and see what happens:

Just as we expected, no test were run. Let’s add the file that will hold the tests. Let’s call the test file test_rational.py. The name is important.

As mentioned in the pytest documentation, the framework uses standard test discovery to find and run tests.

We’re concerned with 2 basic rules in this example:

  1. files named test_*.py in the directory
  2. files named *_test.py in the directory

Let’s run the pytest command again with our new (empty) test file, test_rational.py.

Again, no tests were detected, so no tests ran. Let’s add a test.

If we use the existing smoke test file as a guide, you’ll see a series of tests lists. As a general rule, it’s easier to test the behavior of code that has the fewest dependencies. What do I mean by this?

Looking at the Rational class, you might be tempted to start testing there. However, you’ll see that the implementation of that class depends on another function, gcd.

If a test of the Rational class fails we can’t be sure that the class is responsible for the error. At least not yet. We should drill further into the dependency of the class and start with the “bricks” the foundation of the Rational class is built upon.

This is why gcd is a good candidate. The comments in the function tell us that it’s based on Euclid’s algorithm for finding the greatest common denominator (gcd) of 2 integers.

Since we know the general expectations of how gcd works, we can start with a simple test case. On paper, Euclid’s algorithm predicts the gcd(3,0) will be 3.

Our test file now looks like this:

import rational

def test_gcd_a_0_is_0():
    assert True

If we run pytest again:

So far, so good. Let’s replace the assertion with a real test, but with a clearly wrong answer.

import rational

def test_gcd_a_0_is_0():
    assert rational.gcd(3,0) == 100000

You might wonder why would add a test that is going to fail. We want to verify that the test we are creating is going to run and that if there is an error in the test we’ll catch it.

Consider how blind we would be if we created a faulty test and the test framework ignored the failing test. How much time would we waste building on this false assumption? It’s better to check now, at the start, and catch stupid mistakes before they cost us an arm and a leg.

Isn’t that great? pytest tells you exactly where it fails and why. Let’s repair the test with the correct expected value.

import rational

def test_gcd_a_0_is_0():
    assert rational.gcd(3,0) == 3

Then verify that with pytest:

That’s it, you did it! You created a test and know you know how to build more. Instead of trying to remember each test case and run them manually, you only have to run one command to run all the tests.

That feeling you have right now? That’s the feeling of victory over chaos.

Sign up now for more victory right to your inbox.

Did you find this useful? Sign up and get more Python help!

How to Level Up in Python

How do I, someone who just dabbles in Python and uses it for daily data handling tasks, become an expert in Python?

Anytime you learn a new skill, such as learning Python, you might feel anxiety about wether or not you are “ready”. You’re always looking around at this course or that, wondering “Is this any good?” or “Will I learn the right things?”

You want some way to hone your skills and “level up”. In school you might have a math class where your teacher would throw problem sets at you. You had lots of opportunities to work problem after problem, making corrections and getting (hopefully!) better. Now you know the basics of Python. You can even write a few Python programs by yourself. But, where to go from here? How can you take things to the next level?

An Excellent Way to Improve Your Python Skills

If you want to develop real skill in Python, you need to write as many Python programs as you can. You also need to get feedback about how effective your programs are. There’s no sense in writing defective garbage if you want to get better. You need some way to write lots of programs, get feedback, and be pushed to improve.

Luckily, there’s a superb place for this call Exercism.io.

Exercism.io is a web site that “provides countless small wins”. This is brilliant!

When you are working hard to improve, each win is a bit more momentum to push forward. Believe me, as you progress, you will need to be pushed a little harder to get better each time.

Exercism.io gives you a a lot of Python challenges – over 100 – for you to conquer. Each challenge comes with the tests already written. So in addition to learning how to solve problems in Python, you get to see how unit tests are built along the way.  If you want to become an expert Python programmer then you must learn to write tests.

A Walkthrough of the First Challenge

Go grab the Exercism.io command line interface (cli) tool. This will be different depending on which operating system you are using.

Log in to Exercism.io with your Github account then get your Exercism.io API key.

I created a directory called

exercism

and then another sub-directory under that called

python

.
You’ll next fetch the first challenge (in the

exercism\python

directory:


$ exercism fetch python

Not Submitted: 1 problem
python (Hello World) ~\exercism\python\hello-world
New: 1 problem

python (Hello World) ~\exercism\python\hello-world
unchanged: 0, updated: 0, new: 1

Let’s set the API key so we can submit our answer. This will allow us to track our progress. It will also show others how we solved this challenge. It’s incredibly instructive to see how other people solved their challenges, too.


$ exercism configure --key=

Configuration written to ~\.exercism.json

    --key=
    --dir=~\exercism
    --host=http://exercism.io
    --api=http://x.exercism.io

If you list the contents of the hello-world directory you’ll see:

hello_world.py
hellow_world_test.py
README.md

It’s tempting to jump right in and start writing the implementation in

hello_world.py

. Let’s set a good habit right now: run the tests first!

The README.md contains interesting information about how to run the tests. You will need to install

pytest

, which also means installing a package manager for your local Python distribution (like

pip

). Assuming I’m using Python 2.7, then I would run:


$ python -m pytest hello_world_test.py
============================= test session starts =============================
platform win32 -- Python 2.7.0, pytest-3.4.2, py-1.5.2, pluggy-0.6.0
rootdir: ~\exercism\python\hello-world, inifile:
collected 1 item
hello_world_test.py F [100%]
================================== FAILURES ===================================

_________________________ HelloWorldTests.test_hello __________________________
self = <hello_world_test.HelloWorldTests testMethod=test_hello>
def test_hello(self):
      > self.assertEqual(hello_world.hello(), 'Hello, World!')
E       AssertionError: None != 'Hello, World!'

hello_world_test.py:10: AssertionError
========================== 1 failed in 0.10 seconds ===========================

That looks ugly but it’s expected. You just ran the tests (pre-written by the challenge author) but since there is no implementation the tests failed. Our next step is to provide that implementation.

Every time we make an update we should run the tests, as above. We’ll know very quickly if we made progress or introduced a bug (a regression).

Here’s an example implementation you can use in

hello_world.py

:

def hello(name=''):
    return 'Hello, World!'

Let’s rerun the tests and see how we did:


$ python -m pytest hello_world_test.py
============================= test session starts =============================
platform win32 -- Python 2.7.0, pytest-3.4.2, py-1.5.2, pluggy-0.6.0
rootdir: ~\exercism\python\hello-world, inifile:
collected 1 item

hello_world_test.py . [100%]

<========================== 1 passed in 0.04 seconds ===========================

And that’s that. Let’s push our solution back to Exercism.io:


$ exercism submit hello_world.py
Your python solution for hello-world has been submitted.

Programmers generally spend far more time reading code than writing it.
To benefit the most from this exercise, find 3 or more submissions that you can
learn something from, have questions about, or have suggestions for.
Post your thoughts and questions in the comments, and start a discussion.
Consider revising your solution to incorporate what you learn.

Yours and others' solutions to this problem:
http://exercism.io/tracks/python/exercises/hello-world

I bet you’ll be ready to devour the next one. Good luck!

If you want a more detailed example of writing tests, check out Keep Calm and Add Unit Tests with Python.

Get the next post right to your inbox!

Did you find this useful? Sign up and get more Python help!

Arrrgh! Why Doesn’t My Python Program Work?

I’m having trouble with a tutorial… it doesn’t work!

I can’t figure out why my code isn’t working!

You’ve been banding your head against your desk for hours. The examples seemed so clear, but when you wrote your program it all fell apart. You’ve looked over the code, again and again. Everything looksfine. IT. JUST. DOESN’T. WORK.

You want your program to work correctly. You want to move past this annoying bug. You want to move on and keep learning. What can you do?

You can do a few things when you are stuck. You can write tests while while you write the program. You can talk to someone (or yourself!) else and get their help.

The Solution!

Use a debugger. A debugger allows you to interactively run a program and check the process state. Use a debugger to quickly explore how a program actually works. A debugger helps you understand Python better than passively reading example programs.

A Detailed Walkthrough

In this case, we will use the built-in Python debugger. The Python program we’re running is from a Reddit post, and the code is here.

First, in your console, start your program (we’re using Python 3.6 at the moment):

python -m pdb guesser.py

This starts the Python interpreter and loads the pdb (the Python debugger) module.

You’ll see the pdb prompt:

-> def main():
(Pdb)

This shows you that the program execution starts at the main function definition.

The debugger accepts a number of different commands. The first one we’ll use is the w command – which stands for where, and it will show you the current “line” in the program the debugger is about to execute. It also shows you the current “stack”, or the history of functions the interpreter executed in the program.

(Pdb) w
c:\program files\python36\lib\bdb.py(431)run()
-> exec(cmd, globals, locals)
(1)()
> c:\users\jjeffers\pydebug\guesser.py(1)()
-> def main():
(Pdb)

The bottom most function is the current executing “frame” of the program.

To get to the next line of the program (and have Python execute the current line), press n (or next).

-> if __name__ == "__main__":
(Pdb)

Notice how the function definition was “skipped”, and the debugger jumped to the next executable line.

Enter n again.

-> main()
(Pdb)

Now we’re entered the if statement, because the test for

__name__ == "__main__"

was true. The debugger is showing you that the next line to execute is the call to the “main” function.

Enter s (or step) here. The step command works like next, but instructs the debugger to “step into” any function calls.

-> def main():
(Pdb)

Don’t worry, we’re not caught in a loop here. Enter n to move to the next line inside the main function.

-> print("Guess a number between 1 and 100.")
(Pdb)

Keep using n until you reach the line:

-> while not found:
(Pdb)

You will see the lines for the variable definitions for found and randomNumber. You can use the debugger to query the interpreter for the current value of a variable.

(Pdb) found
False

Let’s move on until you get to the prompt:

-> userGuess = input("Your Guess: ")
(Pdb)

Enter n again, then and enter 3 when prompted.

The very next line is

-> if userGuess == randomNumber:
(Pdb)

Here’s where the debugger really gets useful. Go ahead and query the test expression:

(Pdb) userGuess == randomNumber
False

This shows you where the issue is, but it might still not be clear why that test fails until we look at the operands userGuess and randomNumber.

(Pdb) userGuess
'3'
(Pdb) randomNumber
3

And that’s it – the 2 variables hold different values – one is a string and the other is an integer.

Using the debugger is a good skill to learn. It helps you track down issues in a running program. If you want to add more safety, you need to write tests, too.

If you want a detailed example of writing a test, check out Keep Calm and Add Unit Tests with Python.

Get the next post right to your inbox!

Did you find this useful? Sign up and get more Python help!

Yes, You Should Add Unit Tests To Your Project

Should I go back on what I have in my project and write some tests for it, or just finish the project?

You’ve worked long and hard on your projects only to realize that you didn’t write any tests. You’ve read how important tests are. You probably also know this is a best practice, but it’s so much more work. Even worse, what if the tests show you that there are problems. Then you’ll have to work even more to fix them!

The truth is your project isn’t done. Every software product has bugs – you just haven’t found them yet. Of course, you want to do a good job. You want to show people you know the basics. You want people to know you are ready for the next step. But you know, deep down, the whole house of cards will collapse.

You’ll be exposed as a fraud who didn’t bother to test your work. No employer will touch you. You’ll end up living in cardboard box, down by the river, subsisting on a diet of government cheese.

You want tests. You want a lot of tests that give you confidence that when you make a change you’re not breaking things. You want to run your tests whenever you like. You want continuous integration to run those tests whenever you commit a change. You want the world to see you understand how to make safe changes.

The fix: write ONE test first.

You don’t have to blanket the project with tests all at once. In fact, if you try that, you’ll fail. You’ll lose motivation when you realize just how many tests you should create.

You need to create a momentum of success first. You need to have a small, solid win. From there you’ll pick up steam and get more tests in place.

  1. Find your unit test framework and install it.
  2. Find the part of your project that is the easiest to test.
    • Look for code where you have little or no dependencies. Hint: If it touches a network or file system, keep looking.
    • Find functionality where you can isolate a function or class method. Hint: If it takes setting up helper objects then keep digging into the helper objects.
  3. Create a test file anywhere. Don’t worry about the “right” place to put it.
  4. Run the test. Yes, it will fail.
  5. Write one test in a way that you know it will fail. For example, if you are testing a method that should return a number, have the test expect a string.
  6. Fix the test so it passes. Hint: this might take more than one try. That’s fine!
  7. When the test passes, commit that test.
  8. Take a break. Enjoy this feeling!

That’s it. That’s how you get started. Next step is to keep adding tests, one at a time.

If you want to see a detailed example of adding tests, check out

Get the next post right to your inbox!

Did you find this useful? Sign up and get more tips and help!

How to Switch from “Exercise Coder” to Software Developer

I can do all the exercises, and I understand all the code, but I don’t know how to make a real project.

I cannot start any project, I cannot “build” anything. I feel so helpless. Maybe I’m not supposed to be a developer?

It’s not uncommon for new programmers to reach a point where they master the basics and are left wondering “What next?”

They feel despair or confusion. They look around and realize that taking another course or reading another blog article is going to make the answer appear.

The frustrated “exercise coder” wants to make the next great leap in their skills. They want to learn how to make real contributions and get something working.

An Easy Solution!

Fortunately there’s an excellent source of project work waiting for attention: open source software projects.

You can contribute to any number of software projects as a novice developer. How to Contribute to Open Source is an excellent source for finding and contributing to open source projects.

You’ll gain experience and learn from others while helping out with open source projects.

And there’s a bonus! You’ll develop a growing portfolio of work you can demonstrate to potential employers.

Here’s what you should do, right now:

    1. Follow @yourfirstpr on Twitter.
    2. Watch the tweets, and pick one of the issues that stands out to you.
    3. Make sure you read the How To Contribute guide.
    4. Approach the project organizers and ask if they’d like some help. Optionally, you can combine this a set of changes as a PR (pull request).

All of this assumes you are familiar with Git (and to some extent Github). If you aren’t yet familiar with Git, Github hosts this short introduction guide that will get you started.


Join the Newsletter!

Did you find this useful? Sign up and get more tips and help!

A Very Useful Dictionary of Computing

When you learn a new skill it’s import to have a clear understanding of the the vocabulary.

A recent learnprogramming sub-reddit post asked about which terms are important. (That question itself is superb for learning.)

One response mentioned this dictionary of computing terms – the Free On-Line Dictionary of Computing Terms. This is a very handy resource to have at your fingertips.


Learn To Program Newsletter

Are you interested in learning how to make the leap from manual tester to a test automation engineer? Sign up for tips and tutorials about learning to write software.

Intro to Python MiniCourse – First Steps

If you want to become a test automation engineer, you will have to learn how to write software.

If you’ve never programmed before in any language, it’s sometimes hard just to get started. It’s hard to know where to go, what tools to use, or even what language is best to start with.

This is your chance to take those first few steps towards learning how to program.

Python MiniCourse – First Steps

Sign up now for a Into to Python MiniCourse!

For the next 3 days I’ll send you a daily email with a super simple lesson you can complete in less than 5 minutes.

Each lesson will teach you just enough Python to get you started on your journey.


First Steps: Write Your First Python Program in 30 Seconds

If you want to become a test automation engineers but are still thinking about learning how to program you need to get moving.

You need to take the first step. You need to push a little rock that will start an avalanche of momentum.

You are going to write your first program right now.

Go to Python.org and follow along:

This is an embedded Python interpreter. It’s probably not a tool you would use for anything beyond simple experimentation. You have to admit, it’s a very quick way to try your hand at some simple Python programs.

Intro to Python Webinar

If you want to learn become a test automation engineer, or a Software Development Engineer in Test (SDET), you must learn to write software.

Luckily, you can find many great resources online if you want to start learning about programming.

Sometimes the hardest part about starting a new skill is just knowing where to start.

Maybe you’re wondering:

“What’s the best language to learn?”

“Which course should I take?”

“What the fastest way to learn programing?”

Webinar: Becoming a Test Automation Engineer: Python

On Monday, February 12, 2018 at 1pm I’m conducting a webinar Becoming a Test Automation Engineer: Python hosted by Paul Merrill of Beaufort Fairmont.

I’ll talk about why Python is a great language to learn programming. I’ll also show you some simple examples, tips on how to get started, and ways test automation is done in Python.

If you want to become a test automation engineer sign up soon since seating is limited.

Introduction to Programming Course Comparison

There are many courses available to help you learn how to program.

Here is a list of several available online, in no particular order. None of these courses assume you have previous programming experience.

DISCLAIMER: I receive no compensation for these summaries.

Automate the Boring Stuff (Udemy)

Cost: $10 for the Udemy video course if you go through the link at https://automatetheboringstuff.com/, otherwise $50.

Time to Complete: 9.5 hours

Summary: Comprehensive review of Python through video lectures. The author says the video course covers most of the same ground as the book, but the book’s probably a great alternative if you prefer that medium.

Free Programming Basics Course (Ministry of Test)

Cost: Free

Time to complete: a few hours.

Summary: No frills survey of programming concepts and tools. Course material is delivered by web content. There is no feedback or interaction with an instructor.

Programming for Everybody (Getting Started with Python) (Coursera)

Cost: Free 7-day trial, $49/mo after trial ends.

Time to complete: 6 weeks, 2-4 hours/week.

Summary: Long distance entry level college course. Python is the language used to illustrate concepts with videos, web content, and proprietary courseware. Assignments are graded as pass/fail by a auto-grader process.

Programming Foundations with Python (Udacity)

Cost: Free

Time to complete: 6 weeks.

Summary: Self-paced low-level programming course with video instruction, proprietary courseware, discussion forums. Also features quizes and forum interaction for feedback. “Nanodegree” offered for completion of a curriculum group. Favors lecture format with worked examples by the instructor over interactive application of Python by the student.

Master Fundamentals of Programming for Beginners (Udemy)

Cost: $194.00

Time to complete: 13 hours.

Summary: Comprehensive programming course that introduces C and Python. Relies on video lectures and a “Q&A” feature to review and search questions submitted by other students. Little opportunity to write programs and get feedback.

Try Python (Code School)

Cost: $29/mo, but some courses free

Time to complete: 2-3 hours

Summary: Self-paced entry level programming course focused on Python basics. Features videos, slide downloads, proprietary courseware, and an interactive Python emulator.

Learn Python (Code Academy)

Cost: Free, optional upgrades ($19/mo and $199) for access to technical support, more lessons, and additional material.

Time to complete: 10 hours

Summary: Self-paced entry level programming course focused on Python basics. Features web content, proprietary courseware, and an interactive Python emulator.

Ruby in Twenty Minutes (ruby-lang.org)

Cost: Free

Time to complete: 20 minutes

Summary: Very quick “up and running” tutorial. Assumes you have already installed Ruby and are comfortable with the command line. Nothing fancy here – just enough to wet the appetite for the language.

What is Programming? (Khan Academy)

Cost: Free

Time to complete: less than an hour

Summary: Similar to other Kahn Academy lessons, shows you the theory behind programs, and then begins to dig into some Javascript to manipulate images in an interactive emulator. A non-threatening introduction before getting into the deep end of the pool.

Introduction to Computer Science and Programming using Python (Edx/MIT)

Cost: Free. Optional certificate for $49.00, accredited tuition rate of $300. Textbook (available from amazon.com) is not included in the cost.

Time to complete: 9 weeks, 15 hours/week.

Summary: Self-paced college level course featuring introductory computer science concepts. Designed for students not majoring in CS or EE degree programs. Features lectures, interactive assignments, problem sets, and quizes. A certificate of completion is available (see Cost section). Credit hours available for qualified students.


Learn To Program Newsletter

I’ll help you become a test automation engineer by learning how to program.