The importance of writing tests in the new era of programming

There's a way to use GitHub Copilot with confidence

Published in Food for thought on Oct 8, 2022

GitHub Copilot has been part of our lives for a year now and has changed the way they work for many developers. This offers a whole host of opportunities, but of course also all kinds of risks.

For instance, it generates a lot of code that we don’t always understand exactly what it does, and what the edge cases are. We can figure it out, and we should, of course. But there is another way that can help us gain confidence in how the code GitHub Copilot presents us with works. And that is something we should really do anyway.

Writing tests.

Yes, I know. Writing tests is stupid. Nobody likes to do it and we are far too busy for it. The code we have to write creates enough time pressure. And we have a QA team, so why me?

We’re great at making up excuses not to write tests, but that’s about the previous era of programming. The new era means our role is changing from writing code to designing code. We are, all at a different level, being pushed more and more towards architecture, and less and less towards the code content.

This is a trend that has been going on for some time, but with GitHub Copilot, it is suddenly getting very close very quickly. We are no longer writing code, but we are designing code. And that means we have to start thinking about the code we write in a different way.

Most of us have the intention to pick it up, but never get around to it. Test Driven Development.

Okay, but how do I do that?

Test Driven Development is a way of writing code that is based on the idea that you first write the test, and then write the code to make the test pass. Thanks to GitHub Copilot, we can now write the test first, and then let GitHub Copilot write the code for us.

Let’s take an example. A Kata from CodeWars, for example.

Create a function that takes a positive integer and returns the next bigger number that can be formed by rearranging its digits.

For example:

nextBigger(12) == 21
nextBigger(513) == 531
nextBigger(2017) == 2071

The first thing we do is write the test. We can do this in a few ways. As a PHP developer, I prefer to use Pest PHP. But you can also use PHPUnit, or any other testing framework you like.

it('returns the next bigger number', function () {
    expect(nextBigger(12))->toBe(21);
    expect(nextBigger(513))->toBe(531);
    expect(nextBigger(2017))->toBe(2071);
});

it('returns -1 if no bigger number can be composed', function () {
    expect(nextBigger(9))->toBe(-1);
    expect(nextBigger(111))->toBe(-1);
    expect(nextBigger(531))->toBe(-1);
});

Let’s be honest: this isn’t a lot of work. We can do this in a few minutes.

Now we can let GitHub Copilot write the code for us. Let’s just give it the assignment and expected function signature:

// Find the next bigger number with the same digits
// Return -1 if no bigger number can be composed using those digits
function nextBigger(int $number): int
{
}

And then we let GitHub Copilot do its thing. In my case, it came up with this:

function nextBigger($n) {
    $digits = str_split($n);
    $length = count($digits);
    $i = $length - 1;
    while ($i > 0 && $digits[$i - 1] >= $digits[$i]) {
        $i--;
    }
    if ($i <= 0) {
        return -1;
    }
    $j = $length - 1;
    while ($digits[$j] <= $digits[$i - 1]) {
        $j--;
    }
    $temp = $digits[$i - 1];
    $digits[$i - 1] = $digits[$j];
    $digits[$j] = $temp;
    $digits = array_merge(array_slice($digits, 0, $i), array_reverse(array_slice($digits, $i)));
    return (int)implode($digits);
}

Let me be absolutely clear: this is not code that I would write myself. Luckily, GitHub Copilot proposes 9 other options, and I can choose the one that I like best. But that’s not the point. Now that we’ve written clear tests, we can see if the code works the way it should. That’s a great start.

  Tests\ExampleTest 

 it returns the next bigger number
 it returns -1 if no bigger number can be composed

Tests:  2 passed
Assertions:  6
Time:  0.001362417s

That’s looking great!

What’s next?

Now that we have a working solution, we can start to improve it. We can start to think about the edge cases, and how we can make the code more readable, or how to make it more maintainable.

However, this way of working does offer you an easy way to get started, where you can save yourself a lot of work, and thus iterate quickly. Of course, the quality provided by GitHub Copilot is still not great, and you will probably want to refactor the code again. However, it suffices just fine for getting started.

Next step: Write the tests with GitHub Copilot as well

If GitHub Copilot can write our code, can it also write our tests? Yes, absolutely! In fact, the tests you see above I didn’t write myself, those also come from GitHub Copilot.

Just get started! Good luck!