Who wants to write unit tests?

Who wants to write unit tests?

Not me.

It’s like asking who wants to eat healthy. We all know (or suspect) that it’s good for you, but what are the real benefits?

Writing unit tests is extra work, and not very fun.  And if you start with an existing code base that doesn’t have them, it can be intimidating and frustrating to get started.  And it isn’t always easy.  You might have to spend significant time refactoring and writing mocks and other test doubles to be able to test your code.

 

If you’re skeptical of the value of unit tests, come share your reasons.

If you write unit tests but find they don’t have any real value (or not enough to justify the costs) then let’s talk about why you do it.

If you want to write unit tests, but can’t find the time, or feel like you need help getting started, let me know, and I’ll be your personal trainer.  Book some 1 on 1 time with me.

If you love writing unit tests and the productivity boost and code quality gains they provide, don’t bother coming, unless you want to help convince others.

There are real challenges to writing unit tests but don’t let procrastination or fear be one of them.

 

I’ll be hosting a webinar about unit testing today at 1pm at Hart.com and next Wednesday at 1pm Pacific for everyone online.

Here’s the hangout url https://hangouts.google.com/hangouts/_/one-shore.com/whowantstowriteunittests?hl=en&authuser=0

Ping me if you want an invite in your calendar.

Standardizing tools can lead to testing “synergies”

It’s everyone’s favorite square on buzzword bingo.

The one with the word “synergies” written on it.

But just because managers and consultants overuse a word, doesn’t mean it doesn’t have real value.

I’m talking about standardizing testing tools.

I was just talking with someone about a consulting opportunity at a large company. Their challenge is that they have a bunch of cobbled together testing systems for different teams. They need to build it all under one system. The list of skills needed is miles long:

Java, Javascript, Python, Selenium, Protractor, QUnit, JUnit, TestNG, iOS, Android, Maven, Gradle, Puppet, Chef, Docker, Vagrant, VMWare, Angular, Backbone, …

My response:

It looks like the first big challenge will be standardizing tools.

There could be a lot of easy wins by picking, for example:

* Maven or Gradle for builds
* Puppet or Chef for deployments
* JUnit or TestNG for test runner

That could be quite a challenge for teams who “like what they know” and don’t see the value of change.

But if there are projects with neglected or troublesome build/deploy/test cycles, then standardization could be the price of admission into a concierge service that builds their code, runs unit tests and static analysis, deploys it to a test environment, and runs system & integration tests. The biggest challenge I’ve seen is getting permission and resources for the test environments, and it can be like pulling teeth to find out all the dependencies & data that need to be assembled (or mocked). At the end of it, though, there’s a virtual cycle that can’t be stopped.

And when you have standard tools in place and a smooth build/deploy/test in place, then teams really can start leveraging shared tools.

Synergies achieved. Without layoffs. BTW, they’re looking for additional SDETs in Seattle. Let me know if you’re interested in tackling a big project.

How to reduce the number of mocks for testing

We all know that testing objects in isolation is a good thing. (You should also test objects interacting, but that’s a different subject.)

Testing in isolation allows us to concentrate on testing a behavior without introducing additional complexity. It also allows us to strictly regulate the external state and eliminate potentially unexpected behavior. To accomplish this, we often turn to mock objects.

Mocks can do two main things:

  1. Isolate the object under test from its dependencies
  2. Isolate the object under test from external communication

Let’s say we want to make a self-driving car. We’ll start off with an existing vehicle.


car = new Car(make, model, year)

The first thing it needs is a robot driver.


car.driver = new RobotDriver()

Since the robot driver doesn’t need to take up a seat, we’ll throw him in the trunk so we can have another passenger. And we might as well remove the steering wheel, pedals, and shifter to make room for him. (Assume our robot driver will not malfunction so there is no need for a manual override.)


car.remove(steeringWheel)
car.remove(shifter)
car.remove(pedals)

Now we can get to our first test. We want to check how many passengers can fit into our car now.


assert.that(car.passengerCapacity()).equals(4)

For our purposes, the driver doesn’t count as a passenger.

We probably should have checked the capacity before ripping out all that stuff, and then we could write a more flexible test. We’ll also create a factory that can transform a regular car into a self-driving car.


car = new Car(make, model, year)
initialPassengerCapacity = car.passengerCapacity()
selfDrivingCar = RobotCarFactory.transform(car)
assert.that(selfDrivingCar.passengerCapacity()).is.greaterThan(initialPassengerCapacity)

All well and good, but we’ve done a lot of hand waving. Of course, there is no such robot car factory, and no robot driver (yet). That shouldn’t stop us from testing. And that’s where mocks come in.

What does a driver do?  First we need to define an interface.


interface driver {
startEngine()
stopEngine()
accelerate(speed)
decelerate(speed)
drive(duration)
turnRight(degrees)
turnLeft(degrees)
chatWithPassengers()
}

Now, as long as both a human driver and robot driver can do all of these things, they can satisfy the interface and be substituted for one another by our car.

But you might remember that we don’t actually have a robot driver. (Developers say it should be ready by next week, but they’ve been saying that for a long time.) So we create a mock:


robotDriver = mock(driver)

And now we can test it.


car.driver.startEngine()
car.driver.accelerate(milesPerHour(60))
car.driver.drive(minutes(1))
car.driver.turnRight(90)
car.driver.drive(minutes(1))
car.driver.decelerate(milePerHour(60))
car.stopEngine()


assert.that(car.distanceTraveled()).equals(miles(2))

You can see pretty explicitly here that a driver is a dependency of the car (if we want it to go anywhere.) In this case, our mock robot driver could just be a person with a remote control.

Our goal here is to show that our car works without a human driver and that there is room for an extra passenger. (So that we can obtain additional funding from our investors who want an edge in the ride-sharing marketplace.)

Stay tuned for part 2.

Using GVM to manage Go (golang) versions

I’m testing microservices build with Go [https://golang.org/] lately. So I need to set up a working Go environment.

On a mac, it’s as easy as `brew install go`, but on CentOS `yum install go` will give you an outdated 1.4 version of go.

There are a few tricks to using Go, but the basics are to set two environment variables: GOROOT and GOPATH

GOROOT is strictly not necessary (unless you’re dealing with multiple versions of go, which is officially not recommended.)

GOPATH is kinda like setting your PATH or JAVA_HOME, but GOPATH is additionally tricky because it determines where your dependencies are a installed, so it’s really more a bit like setting M2_HOME (if you use maven.)

Go `go get` is aware of git & mercurial repositories, it can install packages from github for you, but it is only semi-aware — in that it doesn’t understand versions. So you either need to fork each dependency’s repo at the version you need (and merge when you need updates) or just freeze it. So each project needs it’s own GOPATH (and a branch with each depndency tree.)

Enter GVM. Kinda like RVM, NVM but for Go. Here are the steps I use to set it up:

# install go dependencies on CentOS 7.2
yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel gcc perl-ExtUtils

# throw in the dev kitchen sink while your at it
yum groupinstall "Development Tools"

#install GVM (https://github.com/moovweb/gvm)
bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)
source ~/.gvm/scripts/gvm

# install go 1.4 (to be able to build later versions)
gvm install go1.4
gvm use 1.4

# now I can install go 1.6
gvm install go1.6
gvm use 1.6

# create a packageset for my project
gvm pkgset create mygoproject
gvm pkgset use mygoproject

# finally, I can get some work done and build my Go project
git clone git@github.com:fijiaaron/mygoproject.git
cd mygoproject
go install

Test automation advice for distributed teams

While traveling around the USA, I’ve learned a lot about working remotely — on the go.

I signed up with a service called Clarity to offer advice to startups on setting up test automation & continuous integration for distributed teams.

For a limited time, I’ll be offering free 15 minute sessions, but I’ll also be donating all my proceeds to OSSO – the orphanage support services organization that my wife volunteered at in Ecuador.

 

On the road at last

Today we loaded up all our things into an RV (and a 10×20 storage unit) and drove away from our home in Orem, Utah to Winnemucca, Nevada.

15 - 1

It’s a lot farther than you think.  A lot more preparation goes into planning a move like this than it sounds like.  But a lot less than you’d think.  And probably we should have done a lot more than we did.

It’s only the first stop on our year long (or more) plan to travel around the country as a family and see what we can see.  While I work remotely and Kelsey home schools our kids.

Our first destination is Oregon.  To see Crater Lake, and show my family where I used to live.  Then to Selenium Conf in Portland, and then Seattle, and then a meandering line from there to Florida where I have another work conference in December.

That’s a lot of miles — and it doesn’t leave a lot of time for stopping to smell the roses.

As the day of our departure neared, I didn’t think we could do it.  While I worked, Kelsey cleaned the house and put into storage (or sold) all that we had.

I was supposed to fix up the RV.

I ordered & installed solar panels, a new inverter and batteries capable of running my office on wheels.  But I didn’t get it hooked up to the house power.  So we have 4 100 watt flexible solar panels mounted on the roof with 3M Dura Lock (think super velcro) generating power to loose wires, a charge controller (Midnite Solar Kid) in the drawer, and a 2000 watt Samlex inverter & 12 volt, 150 amp hour batteries mounted in a storage compartment and not hooked up to either the solar panels or the house electrical system.

I was also supposed to install our tow package.  It didn’t come until last weekend, and I didn’t get it installed either.  But Kelsey got the house done and we put our last load in storage this morning and checked out with the landlord a bit late.  By the time we left, it was 11:30am (not nine).

Because the tow package wasn’t hooked up, I drove the truck behind Kelsey in the RV with the kids divided between us an switching back and forth at every stop — of which there were many.  8 hours into a 5 hour trip, I calculated we were averaging 35 miles per hour.  Finally we pulled into an RV park in Winnemucca, and we made our destination just before dark at 8pm.

Not only was it too late, but there was no pool.  And it meant missing a full day of work (plus a half day yesterday where I helped finish cleaning & packing.)

Everyone was in meltdown mode, except baby Mikey who was happy to be out of his car seat and went to bed quickly.  Kelsey is frazzled from driving the RV for 9 1/2 hours — which is much more demanding than driving a regular car.

But now everyone is sleeping happily, and hopefully ready to continue our journey.

I’d hoped to drive to an Opal Mine in the morning and work there tomorrow, but we’ll stay in Winnemucca and take it easy, and then maybe put some miles on in the night.  Rather than making travel easier, an RV seems to just make it slower

I want to get to our destination in Oregon by Sunday morning so I can go to church and see if I can meet anyone I knew back when I was in school.

We still have piles of stuff all over that we need to figure out how to stash or learn how to let go of.  And we still need to build bunks for the kids.  But we made it.  It’s less about having the right plan and more about committing to do something and then do it.

Using pyenv with virtualenv and pip cheat sheet

I made some notes on how to use a specific python version with pyenv and using virtualenv to manage packages.

using pyenv

https://github.com/yyuu/pyenv

installation

$ git clone https://github.com/yyuu/pyenv.git ~/.pyenv

initialization


$ export PYENV_ROOT="$HOME/.pyenv"
$ export PATH="$PYENV_ROOT/bin:$PATH"
$ eval "$(pyenv init -)"

use command completion


$ source ~/.pyenv/completions/pyenv.bash

(homebrew on mac)

$ mkdir ~/pyenv/completions
$ cp /usr/local/Cellar/pyenv/20150601/completions/pyenv.bash ~/.pyenv/completions/pyenv.bash

use pyenv to install python versions


$ pyenv install 2.7.10
$ pyenv install 3.4.3

choose a python version with pyenv


$ pyenv shell PYENV_VERSION=2.7.10

upgrade pyenv


$ cd ~/.pyenv; git pull

(homebrew on mac)

$ brew upgrade pyenv

run `pyenv rehash` when you install a new python or binary package


$ pyenv rehash

install pyenv-pip-rehash to rehash automatically when you use pip

(as pyenv plugin)

$ git clone https://github.com/yyuu/pyenv-pip-rehash.git ~/.pyenv/plugins/pyenv-pip-rehash

(homebrew on mac)

$ brew install homebrew/boneyard/pyenv-pip-rehash

install pyenv-virtualenv


$ git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv

intialize pyenv-virtualenv


$ eval "$(pyenv virtualenv-init -)"

(homebrew on mac)

$ brew install pyenv-virtualenv

create a virtualenv with pyenv


$ pyenv virtualenv 2.7.10 my-virtual-env

list existing virtualenvs


$ pyenv virtualenvs

use a virtualenv


$ pyenv activate my-virtual-env
$ pyenv deactivate my-virtual-env

delete a virtualenv


$ pyenv uninstasll my-virtual-env