Skip to content

Let's Build Stuff and Test - Part 1

Recently, I wrote about the importance of tests in code and I want to demonstrate my way of working that makes it possible to test small chunks of code. This isn't going to be a definite how to guide on writing tests, but instead be more about knowledge sharing and inspiration for writing tests.

Now before any code is to be written, let's look at and analyze what is going to be built. To keep the domain simple enough to follow, but complex enough to show off the strengths of testing, I will be creating a simple invoice service that generates invoices for my customers. I will implement this in PHP because I enjoy a challenge in writing beautiful code in a language that doesn't have as many nice features and syntactical sugar as say for example C#. And finally, normally there would be a "product owner" to define the domain (business rules), but I'll be playing both roles in this.

So let's define the domain of this invoice service (which most likely does not reflect real world scenarios). We will have invoices, and invoices will definitely contain a customer, and an itemized list of products, services, campaign offers, and so on. The invoice will calculate the total price and show the taxes that were applied. Then we have the customer, which will have a name, address, and phone number that is required. And finally, we will start with implementing the products that are being sold to the customers. In the future, we might have a service or offer that will need to be added to the invoice, so we will not hardcode the type of items being added to the invoice, instead using an interface since the invoice shouldn't be concerned with what is being added to it.

I think that is a good enough start of the domain model to get some interesting code being written. I will save that for the next time though as I would love to hear your feedback on this so far.

Weapon of Choice for PHP: Netbeans

As a "sort of" prerequisite to my upcoming articles about PHP, I'm going to talk about my preferred development environment when working with projects in PHP.

Now I usually only have a few requirements for an IDE when writing code and those are smart intellisense, stable, and organized project file(s) that doesn't clutter your workspace. Netbeans have fit those requirements quite nicely for the past few years. The personal experience that I have had with Netbeans that I really like is that it has worked the way I want it to, even when my way of working has been flexible and changing. It always seems to find a way to adapt to how I want to work.

In the past, I would simply use it as a fancy text editor with intellisense, and then upload the files to a webserver through Netbeans since it had an easy upload function once you configured it. I don't like to run a full web stack on my local development machine because I like to keep the number of running programs and services to a minimum, especially in a Windows environment. So nothing too complicated but I can do better nowadays thanks to the different way I work today. Let's make Netbeans able to run our tests with PHPUnit using only the PHP-CLI.

Windows instructions:
Note: At the time of this writing, the latest PHPUnit doesn't work with the current stable version 8.2 of Netbeans. I had to use a nightly dev build instead.

  • First thing we will want to do is make sure the PHPUnit plugin is installed in Netbeans. This can be found in Tools -> Plugins under either the Available Plugins tab or the Installed tab.

  • After that, we need to download PHP and extract the zip archive to a simple path like "C:\PHP7.1.4\".

  • Next, we will download the PHAR file for PHPUnit. I placed the file in the following location: "C:\PHP7.1.4\phpunit\"

  • Then let's create a phpunit.bat file in the same folder where phpunit.phar is located with the following contents:
    @echo off

    set PHPEXE=C:\PHP7.1.4\php.exe

    "%PHPEXE%" "C:\PHP7.1.4\phpunit\phpunit-6.1.0.phar" %*

  • Finally, let's tell Netbeans where this .bat file is located for PHPUnit. The dialog below can be found under Tools -> Options.

That is the minimum needed to get PHPUnit configured for Netbeans. Let's try using it in a new PHP project as there is some configuration that needs to be done per project.

First, after creating a new PHP project or opening an existing one, we will want to go into its properties and enable PHPUnit as a Testing Provider and add a test directory as shown in the image below:

Now, if you are following along with a new project, let's add the following files to our project.
Source Files: main.php
<?php
function add4($x)
{
        return $x + 4;
}
?>

Test Files: Bootstrapper.php
<?php
chdir('/Users/RJ/Desktop/Environment/TestsProject'); // Put path to your project source files here

require('main.php');
?>

Test Files: FirstTest.php
<?php
use PHPUnit\Framework\TestCase;

final class FirstTest extends TestCase
{
        /**
         * @test
         */

        public function can_add_4()
        {
                $this->assertEquals(10, add4(6));
        }
}
?>

Before we move on to running the tests, I want to explain about the "Bootstrapper.php" in Test Files. This file is needed to setup the application environment when running tests. This is configured in the Project Properties -> Testing -> PHPUnit dialog under "Use Bootstrap". Normally, I have the chdir() call and register autoload inside the Bootstrap file, but to keep things simple I'm just using a simple require call.

Now let's run the tests and see what we get.

The test passed! We finally have our first running test in Netbeans without using a webserver. There is one more thing we can do to make running tests even better. And that is to install Xdebug so that it is possible to debug our tests when something isn't going quite right. But I will save that for the next time.

Suggestion Box

Here you can suggest topics that you would like for me to cover in the comments below.

The only thing I'm not likely going to cover is any topic that is specific to a framework that comes with everything including a "kitchen sink" (with the exception of AngularJS, because pure HTML and JS is just horrible).

TESTS!

There comes a time in a developer's adventure where he or she will stumble upon a testing framework and think, "Tests are a great idea, I should start writing them." But in my case, I begin to realize that starting to write tests can be challenging. This is usually due to multiple reasons including having to restructure one's code, what to test, mocking external services, etc. And with that list of reasons, I start to rationalize that maybe skipping tests is okay, since it seems like a huge upfront cost and a bit of overhead for unknown value. If I would have known years ago what I know now, I would have told myself that the rationalization is ridiculous and just start writing tests because they are totally worth it.

So where does the most value come from in tests for me? As important as it is to test the normal scenarios in my domain code logic, I find that it is even more important to test invalid scenarios in my domain. Does my code reject invalid inputs correctly and gracefully? Did I make sure to cover all possible scenarios that include invalid ones? These things are boring to manually test every time and over time, I will start to assume that it will always work this way in the future. That is a dangerous mindset to get into, as I will make a small change somewhere in the code that will change the assumptions that the existing code has and because of that, it will most likely introduce bugs or security issues.

With that said, I plan to write a series about how I write code and tests. But until those are published here, I will leave you with some probably obvious but solid advice about writing tests. It's good to have many small tests, and test the smallest bit of code that is possible. I personally haven't written any big tests but I can imagine that the bigger the test scenario, the more likely that the test code will need to be updated if the domain rules change. Focus the tests on the domain rules and logic. It's not very interesting to test code that saves some data to a persistent storage like a database, and avoiding these kind of tests makes it easier to have mock objects for things like persistent storage.

Introduction

Welcome! I'm Richard Hartfield, also known as RJ, and I have been writing code since I was about 12 years old or so. I initially got into programming because I wanted to create a game, but I got into web development shortly after that. I enjoy writing code that performs quickly but also balances the readability of the code as well.

I've started this blog to share with you my experiences and opinions while working on projects. However, I'm going to write about the things that I think tend to be more complicated. For example, understanding the value of and writing tests, which is a topic I want to cover soon. I will also write about my interpretations and opinions on a variety of concepts and tools, which I'm not claiming to be an expert in, but instead to give my perspective on it and I hope that others can give their perspectives too.

I hope that this blog can serve as a great inspiration to you and that you will want to join for some discussions in the comments.