Developing on Staxmanade

Approval Tests - Command Line Tool (CLI)

(Comments)

In my previous post I introduced Approval Tests using the Approvals.NodeJS variant of the tool.

In this post I'd like to go over how you can use the command line version of Approvals.NodeJS for several different scenarios.

First thing first (How to Install)

Globally install approvals via npm.

npm install -g approvals

Now that you have it installed, let's go over some scenarios that you can use the approvals tool.

Scenario 1: Compare JSON files downloaded from a web server.

Let's say you want to see a quick file diff between two api requests.

You can use curl to download the file and pipe (|) it to the approvals CLI tool. We give it a name parameter which is used to generate the file name used to save to.

So if you were to run:

curl https://api.github.com/orgs/approvals | approvals githubOrg

This would generate two files:

githubOrg.received.txt which at the time of this writing would look like:

{
  "login": "approvals",
  "id": 36907,
  "url": "https://api.github.com/orgs/approvals",
  "repos_url": "https://api.github.com/orgs/approvals/repos",
  "events_url": "https://api.github.com/orgs/approvals/events",
  "members_url": "https://api.github.com/orgs/approvals/members{/member}",
  "public_members_url": "https://api.github.com/orgs/approvals/public_members{/member}",
  "avatar_url": "https://avatars.githubusercontent.com/u/36907?v=3",
  "description": null,
  "name": null,
  "company": null,
  "blog": "http://approvaltests.com",
  "location": null,
  "email": null,
  "public_repos": 13,
  "public_gists": 0,
  "followers": 0,
  "following": 0,
  "html_url": "https://github.com/approvals",
  "created_at": "2008-11-27T06:03:58Z",
  "updated_at": "2014-12-28T03:02:33Z",
  "type": "Organization"
}

and an empty githubOrg.approved.txt file.

Note when you first run this command you are prompted with the received file compared to the empty approved files; however, on an initial run, you can use the --forceapproveall argument to avoid the diff step and force all the contents of the received file into the approved file.

Now if the remote file were to change on you and you run the below command again:

curl https://api.github.com/orgs/approvals | approvals githubOrg

You would get a diff between the the originally approved file and the newly downloaded file.

Scenario 2:

Ok, well I actually have another great scenario for using the approvals CLI, but I believe it deserves it's own post as I'm going to introduce some nifty configuration on a Mac that I've used to setup my own development servers automatically.

Until next time...

Approval Tests - Overview

(Comments)

I first started using the .Net version of Approval Tests and found so much value in it, I created a port of the tool that I can use in Node.JS. This post is intended as a rough overview of Approval Tests, and will be using the NodeJS port in my examples below.

There is support for other programming languages, so head over to the Approval Tests site at ApprovalTests.com and check them out.

What are Approval Tests?

At it's core, Approval Tests are a very different way to execute the assertion step of a unit test.

Think of this as another tool in the bag and not a replacement for the good old fashion assert.equal(...) or your favorite assertion tool. But for certain types of tests, it IS the best tool to grab.

Typically, when we create assertions in our unit tests, we assert on very specific things. This property equals that value.

With Approval Tests, you can take whatever output you're wanting to Assert against, turn it into either a string representation or an image (say screenshot of app), and use our favorite diff tool to compare it with the previously approved version.

The diff tool is a great way to visualize change between failing/approved data which can help to raise the level of abstraction of your test. Instead of comparing a single value in an assertion, we can serialize an entire object graph to a string and use the diff tool to review any changes to the diff of the previously approved version.

The work to find and start up your favorite diff tool comparing previously "approved" files is where the libraries provided by Approval Tests come in handy.

Let's walk through an example

If you've done any testing before, by now you have probably heard of the AAA (Arrange, Act, Assert) style of tests. Below I've contrive a sample test using the AAA style in JavaScript.

var assert = require('assert');
describe("when testing something", function(){
    it("should do something special", function(){

        // Arrange
        // setup the initial state for the test
        var obj = { valueA: "test", valueB: 1234 };

        // Act - Do some business logic on the object
        obj.valueC = true;

        // Assert - verify the state of the item under test
        assert.equal(obj.valueA, "test")
        assert.equal(obj.valueB, 1234);
        assert.equal(obj.valueC, true);
    });
});

At a high level, if you are writing tests with an object, and have a way to translate that object's state into a text or image representation, wouldn't it be great if you could save that state into a file, essentially locking down the state of the test?

This would allow future runs of the test to easily detect a change by comparing the previous state with the new state (strings of course) - but using the power of our diff tools to quickly highlight what is different.

Let's turn our AAA test above into an Approval Test

var approvals = require('approvals');
describe("when testing something", function(){
    it("should do something special", function(){

        // Arrange
        // setup the initial state for the test
        var obj = { valueA: "test", valueB: 1234 };

        // Act - Do some business logic on the object
        obj.valueC = true;

        // Assert - verify the state of the item under test
-        assert.equal(obj.valueA, "test")
-        assert.equal(obj.valueB, 1234);
-        assert.equal(obj.valueC, true);
+        approvals.verifyAsJSON(__dirname, "sampleTest", obj);
    });
});

Notice how the 3 assert's turned into 1 approvals.verifyAsJSON?

How Approval Tests Work

Approval Tests works by taking the object or value you're trying to verify, serializing it to a text file (or image) and saving it to a file labeled with the name of your test and *.received.txt. It will then try to compare this *.received.txt file with a *.approved.txt file. If the file doesn't exist, then we will see a diff tool present with our received file on the left and an empty approved file on the right.

At this point we have to choose between a number of options:

  • We could take the received output and copy/save it to the approved file. Essentially approving the test.
  • We may only want parts of the received file, and copy over just the parts of what we want to the approved file.
  • Or we do nothing as we want to start over...

Now we run our test again and if the test passes - then we know that we've finished as what was re-generated in the received file matches the approved file. But if we see our diff tool appear, we can analyze the differences in the diff tool and determine if we need to either adjust the approved file or adjust our code that generates the received file.

If the above explanation still isn't clear, I'd recommend watching @LlewellynFalco's video's on the topic that can be found at approvaltests.com. He does a good job describing the concepts.

Next Steps!

Browse the github org, watch videos or read documentation on approvaltests.com.

Happy Approving!

Custom Static Blog Generator - No Longer Using Octopress

(Comments)

TL;DR

In summary I left my Octopress blog behind quite a while ago, and this site has been statically generated with a custom tooling build up around gulpjs and node.

Some of the details...

After I migrated from Blogspot to Octopress I started running into workflow issues and other issues that turned me off from Octopress/Jekyll (at least for my own site).

It was also right around the time that GulpJS came out and I needed a project to play around with...

So I did what every developer does. I wrote my own.

Using Approvals.NodeJS to capture previous renderings of the Octopress generated version of staxmanade.com, I was surprised at how quickly I ported my Octopress generated site to a new custom static site generator.

I'm not writing this to convince you to leave Octopress for anything (especially my home-grown tool), but felt compelled to get a blog post out describing some of the cool little features I've implemented.

Personal struggles with Octopress:

  • Octopress site generation was too SLOW for me. There's even a helper rake task that moves your posts to a temporary folder to exclude from generation when you want to quickly see the post you're working on generate fast, but this just bothered me from a fundamental level.
  • I'm not a Ruby developer and don't have the ability or desire to fork/maintain Jekyll or Octopress. I wanted to have something that I pretty much owned. (yea - that comes with a larger maintenance burden, but meh - I'm a developer and its part of the process)
  • Disliked that every time I rake gen_deploy I didn't know the exact code-diff that was changed since the previous version. I'd like to know exactly what files have changed and how they have changed before they get deployed. (again, there's probably a solution here, but didn't really care to dig deeper)
  • There's an issue on Windows where you end up mucking around with the codepage, which made working on things a bit of a headache.

So what did I end up with?

I now have a statically generated site all powered by gulp and a small library/command line tool I've thrown up here: Togglejs.

How is this better ~err~ different?

  • Regenerating my site only takes about 6 seconds (as opposed to the Octopress 30+)
  • I learned gulp, and node.js streams along the way.
  • Built by myself — which was a good for the learning experience.
  • Don't have to set the codepage to 65001 for Windows machines.
  • Series support.
    • I've implemented two different features for supporting a series. One allows me to control through YAML front matter posts and how they tie into a series topic. Another feature allows me to write out a series in a single markdown file, where I can specify a delimiter to split the articles up by. I may blog more about these in the future as they're a feature I've quite liked and was relatively easy to implement using my custom site generator.
  • Easy post tagging for a custom feed that gets cross-posted to elegantcode.com
  • The tog is easy to extend with custom commands and has a number of pre-built commands already ready to go.

Since I've not put a huge amount of time into it - and I haven't exactly developed it to be a competitor to Octopress or other static site generators, it pretty much has just what I need it to have at the moment and not really anything more.

How is this worse?

  • I have to maintain it (this is both a blessing and a curse) - don't get the benefits of bug fixes by hundreds of contributors to Octopress.
  • I haven't yet ditched the Octopress theme, so that change will be coming at some point.
  • I don't have any automated process to deploying changes. So I can't just create a post on my phone, save to my repo and expect it to automatically show up online - but have ideas on how to do that.
  • My gulp watch is not working correctly and it's not yet wired up to livereload which would be a nice next step...

BUT...

This is my site so it's all up to me to make it right...

It's been a pleasure to build this up and just a fun little project to hack on (as if all the other OSS projects I hack on aren't enough).