My First Unit Test … also my second and third.

Photo by Chris Liverani on Unsplash

Test-driven development was my first exposure to coding. It came in the form of freecodecamp lessons on HTML, and you had to write the correct code so you could get to the next lesson. Some unit tests checked your code before being able to get to the next lesson.

I found more test-driven development while attending the Flatiron School’s 15-week immersive Bootcamp for full-stack development. Here I got tests to pass in Rspec ( for Ruby ) and Mocha ( for JavaScript )in labs designed to teach you certain pieces of the development process and make sure you could debug and figure out how to make something work.

My web development world was shaken up when it came to working on my first project. You had a general outline of the features of the application, rubric for how you would be graded, but tests were non-existent. After all, how could someone write tests for an application that hadn’t been conceived yet?

This was my first look at behavior-driven-development. “I want the app to ( DO SOMETHING ) when you click ( ON SOMETHING ).” There were no tests that needed to be passed but based on what we were trying to build we knew it needed to behave in a certain way.

I had mixed reactions.

On the one hand,

It was nice to not be boxed into a particular design structure where certain things needed to happen in a certain way in order for tests to work. If I had a nickel for every time I needed to return “Bob Johnson is 41 years old.” and I forgot the . at the end and failed a test as a result I’d probably have enough money for a new monitor. It was nice to be able to talk about how the app needed to act in the hands of a user and then work backward to create the code which gave us that result.

On the other hand,

Left to my own devices without a nice foundational structure to keep me developing with good practice…. I wrote some less than impressive code to get some functionality working. Thankfully you can always go back and re-factor things once they are behaving as you’d expect.

Since then, behavioral driven development has been the way I have functioned since things I’m working on are primarily side projects. Still testing and specifically learning how to write unit tests has always been something that interested me.

Creating meaningful tests for applications can help stay together as they grow. The larger and more interdependent your codebase gets the more likely there is something that is going to go haywire somewhere else if you change something here .

Testing A React Side Project

I’m 90% of the way through a side project where I dove deep into working with React, Redux, Hooks, and Google Firebase. To bring this learning full circle I decided to write some unit tests. I used create-react-app to generate the project so implementing testing becomes super easy.

Setting Up Some Testing Utilities

To get started I installed Enzyme. A testing utility package for writing and working with JavaScript tests. To install I used npm and installed enzyme as well as an enzyme adapter that corresponds to the version of React you are using. npm i enzyme enzyme-adapter-react-16

To finish setting up enzyme you simply need to configure Enzyme with the Adapter you want to use. This is done in the test file you would like to use enzyme in.

import Enzyme from 'enzyne';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({adapter: new Adapter() })

And were set. Now I’ll show you the first three tests I wrote and a little about the functions they use.

In All Their Glory

My first test was written about a navigation bar. I wanted to check that if a user was NOT authenticated, they got two nav links ( Login and Home ).

To do this I needed the help of a few testing functions.

Describe()

Takes two arguments:

  1. a string describing the extent of what we are testing ( I named it my component name)
  2. a callback function that is going to be where we keep the meat and potatoes for the tests.

It()

Takes two arguments:

  1. a string describing what should happen when when we execute the test function we’re about to pass in as argument 2
  2. a callback function where we are going to write our testing logic.

beforeEach()

Takes one argument:

  1. a callback function to be executed before each testing function and its contents made available to the test function immediately following. For example, if we set a variable we are going to have access to that variable in our it() function.

shallow()

Takes one argument:

  1. JSX code representing a component you would like to shallowly render. Shallow renders are going to give you just the basics here. No props, no state, nothing below the first level of your code. ( think about what the spread operator might give you )

With these tools in our belt, we can work on our first test and see if the component is going to render 2 <NavigationItem/> components when a user is not authenticated. Let's break down the it() function.

it(“should render two <NavigationItems/> when a user is NOT authenticated”, () => { expect(wrapper.find(NavigationItem)).toHaveLength(2); });

The first argument describes what we want to see when this test runs. Our second argument is where the real magic of the test is happening. Here we use expect() to check for a certain return and ultimately give us a pass or a fail on our test. So… what are we expecting? We are going to check our shallow copy of <NavigationItems/> for NavigationItem components and we are expecting to find two of them.

Boom first test finished.

Testing can, of course, get much more complicated, and in my second and third tests, I experiment with the setPropsmethod to pass a component certain props to check if the results have changed. For example, if a user is logged in they should see 3 <NavigationItem/> components and one of them should be the logout link.

Testing is a deep rabbit hole filled with lots of offshoots and ways to make things very complex and frustrating very quickly. My advice is to keep testing simple. Testing should be there to make sure you don’t wreck something you didn’t think was connected to the piece you were working on. It’s there to make sure you are consistently getting a result. I for one am very excited to work on writing more tests after I’ve finished certain components to make sure I can continue to grow an application without losing core functionality. There is something to be said for being able to run a test suite and see if anything is not functioning versus clicking around you app and hoping not to miss something as you are testing things manually.

Happy Hacking!

Resources:

Connect with me:

https://www.twitter.com/IamMisterClean

--

--

Get the Medium app