Thank you for signing up!

Thank you for signing up to the my Python mini-course!

I hope these simple lessons will help you get on the way to becoming a test automation engineer.

If you have any questions, get hung on any problems, or something just isn’t clear please send me a message let me know.

Ruby & Rails Version Matrix

“I’m stuck with upgrading a Rails app from 3.x to something – anything! – newer. Just #$&! kill me now.”

Chances are you will be given a limping Rails application written years ago by someone else that never made the upgrade to more recent versions. It’s a pain in the ass to figure out which version of Ruby to use for the version of Rails you are upgrading to.

This is a summary of several sources for which versions of Ruby are required and recommended for different Rails releases.

Rails version Ruby version Ruby end-of-life Rails end-of-life
6.0.0.beta1 >= 2.5.0
5.0.0beta1 to 5.2.2 >= 2.2.2
4.2.1 to 4.2.11 >= 1.9.3, 2.2 recommended
4.1 to 4.2.0 >= 1.9.3, 2.1 recommended
4.0.5 to 4.1.0.rc2 >= 1.9.3 February 23, 2015 4.1.x December 18. 2015
4.0.0.beta1 to 4.0.4 >= 1.8.7 June 2013 4.x March 20, 2017
3.2.22 to 1.8.7, 2.2 recommended
3.2.13 to 1.8.7, 2.0 recommended
0.8.0 to 3.2.13.rc2 1.8.7 June 2013 3.2.22 June 16, 2015

Upgrading your Rails application is a complex process that can significantly benefit from structured project management and thorough software testing. The right tools in these categories not only make the upgrade smoother but also ensure that your application maintains its functionality and reliability throughout the transition.

Project Management Tools: Organizing and tracking the progress of your Rails upgrade is crucial. Effective project management tools help you outline each step of the upgrade process, from initial planning to final deployment, ensuring that no detail is overlooked. These tools enable teams to stay on schedule, manage resources efficiently, and maintain clear communication. For an in-depth look at how project management tools can transform your Rails upgrade project, read more about project management tools here.

Software Test Management Tools: With the myriad of changes that come with a Rails upgrade, having a robust test management strategy is indispensable. Software test management tools facilitate the creation, execution, and monitoring of test cases, making it easier to identify and address potential issues early in the upgrade process. These tools help ensure that your upgraded application performs as expected, without introducing new bugs or regressions. Discover how software test management tools can streamline your testing process by reading more about test management tools here.

Leveraging these tools effectively can significantly reduce the challenges associated with upgrading Rails applications, leading to a more efficient, reliable, and successful upgrade project.


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

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 is the implementation and 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 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 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 * in the directory

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

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.

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 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. 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 ahead and sign up using your Github account. You’ll be asked to accept terms and conditions. Once you’ve done that, you should see a list of tracks. Find the Python track and click it.

Click the “Join the Python track” on the next screen.

You’ll see a dialog that asks if you want to use Mentored Mode or Independent Mode. Select Mentored Mode if you would like to a more structured experience where others provide feedback. Independent Mode is more of a work-at-your-own-pace model.

You will then see the page for your Python track.

Click on the “Hello World” section. You’re almost ready to install the command line interface (cli) tool. On the next page, look for and click the “Begin walk-through” option.

This will start a short series of steps that will guide you to installing the command line tool, which you will need to submit your answers and demonstrate progress.

To complete the installation, you will need your API key.

I created a directory called


and then another sub-directory under that called


You’ll next fetch the first challenge (in the



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

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

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

The contains interesting information about how to run the tests. Assuming I’m using Python 2.7, then I would run:

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


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

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

And that’s that. Let’s push our solution back to

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:
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.

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):

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

You’ll see the pdb prompt:

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\ -> exec(cmd, globals, locals) (1)() > c:\users\jjeffers\pydebug\ -> def main():


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__”:

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

Enter n again.

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

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.

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.”)

Keep using n until you reach the line:

-< while not found:

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.

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

-> userGuess = input(“Your Guess: “)

Enter n again, then and enter 3 when prompted.

The very next line is

-> if userGuess == randomNumber:

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

(Pdb) userGuess == randomNumber

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


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.

View all posts by James Jeffers

Published March 5, 2018February 1, 2019

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

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.

A Very Useful Dictionary of Computing – James Jeffers Consulting

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.

View all posts by James Jeffers

Published February 22, 2018February 1, 2019

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 and follow along:

You do not have sufficient freedom levels to view this video. Support free software and upgrade.

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.

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, 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 (

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 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.