Ad/iklan :

3gp Mp4 HD
Play/Download
Live 3D App
Search.Pencarian Menu

Add text send email to rh3252705.adda@blogger.com or Click this (Text porn Will delete) | Tambah teks kirim email ke rh3252705.adda@blogger.com atau Klik ini (Teks porno akan dihapus)
Total post.pos : 16329+

[Go Make Things] Don't test implementation details

One of the biggest roadblocks I've personally run into in testing JavaScript—the thing that grinds my testing process to a halt—is fretting over implementation details and code coverage.

Today, I wanted to talk about why they don't matter. Let's dig in!

This article is part of an ongoing series of JavaScript testing. In past articles, we looked at buildless testing, an overview of testing approaches, how to write unit tests, how to organize tests, and TDD.

An example of an implementation detail

Looking at the calculator.js library that we've been testing throughout this series, we have functions to add(), subtract(), multiply(), and divide() some numbers.

// returns 10  let total = add(4, 6);  

Let's imagine that we wanted to make sure that if someone passed in a non-numeric value, the script didn't break…

let total = add(4, 6, 'abc');  

Under the hood, we might try to use parseFloat() convert numeric strings to a number.

We might also add a Number.isNaN() check before using a number, and skip it if it's not a number.

/**   * Add two or more numbers together   * @param  {...Numbers} nums The numbers to add together   * @return Number            The total   */  function add (...nums) {  	let total = nums.length ? nums.shift() : 0;  	for (let num of nums) {  		num = parseFloat(num);  		if (Number.isNaN(num)) continue;  		total = total + num;  	}  	return total;  }  

Now, if we pass in numeric strings, they get converted to numbers, while non-numeric strings get ignored.

// returns 10  let total = add(4, 6, 'abc');    // returns 6.15  let tax = multiply(123, '0.05');  

Testing the new behavior

We can write tests to ensure that library behaves the way we would expect when strings are passed in…

it('Should skip non-numeric values', function () {  	expect(add(4, 6, 'abc')).to.equal(10);  	expect(add(4, 6, '8')).to.equal(18);  });  

And if we're using TDD, we would have written these first, then written our code.

But what happens when we get to the refactor phase?

Changing how the code works under-the-hood

Let's say we look at this bit of code repeated in each of methods…

num = parseFloat(num);  if (Number.isNaN(num)) continue;  

And decide we want to abstract it into some sort of internal function.

/**   * Remove non-numeric strings from the array   * @param  {Array} nums The original array   * @return {Array}      The cleaned array   */  function cleanNumbers (nums) {  	let cleaned = [];  	for (let num of nums) {  		num = parseFloat(num);  		if (Number.isNaN(num)) continue;  		cleaned.push(num);  	}  	return cleaned;  }  

In our methods, we use the cleanNumbers() method to get a clean array before we do any math.

function add (...nums) {  	let total = nums.length ? nums.shift() : 0;  	nums = cleanNumbers(nums);  	for (let num of nums) {  		total = total + num;  	}  	return total;  }  

Test behaviors, not implementation details

How would you modify your tests to account for this? You wouldn't!

The external behavior of our library hasn't changed. How you handle numeric strings is an implementation detail. As long as the behavior is the same, the way you get there doesn't really matter (from a test perspective).

Sometimes folks will fixate on how to test the cleanNumbers() function, which is not exported from the library and thus can't be accessed directly by the test. A lot of testing frameworks even have ways you can "peek in" to your library to do that.

Don't do that!

The cleanNumbers() function is a detail. If you test it directly and change it in the future, you'll need to rewrite your tests even though nothing about the external behavior of the library has changed.

For this reason, code coverage, the percentage of your library covered by a test, it also a bit of a meaningless metric.

Many testing libraries will include functions used in other functions as part of their coverage assessment now. Some will not. Either way, it doesn't particularly matter.

If your tests cover 100 percent of the external behaviors of your library and fail for meaningful reasons, you're good.

You can download the source code for today's article on GitHub.

Cheers,
Chris

Want to share this with others or read it later? View it in a browser.

Share :

Facebook Twitter Google+
0 Komentar untuk "[Go Make Things] Don't test implementation details"

Back To Top