7 Layer Testing
Definition:
Numerous tests depend on the functionality of a single unit, typically incidentally. A single change in the code often breaks many tests in the build. Often exhibits itself when a team finds that even trivial changes to a system results in exorbitant effort to get back to a green build.
Code Example:
// Subject under test
var _ = require('lodash')
function annualProfit (year) {
return _.sumBy(_.range(1, 13), function (month) {
return monthlyProfit(year, month)
})
}
function monthlyProfit (year, month) {
return _.sumBy(_.range(1, 32), function (day) {
return dailyProfit(year, month, day)
})
}
function dailyProfit (year, month, day) {
var transactions = repo.find({year: year, month: month, day: day})
return _.sumBy(transactions, function (transaction) {
return transactionProfit(transaction)
})
}
function transactionProfit (transaction) {
return Math.round(transaction.price - transaction.cost)
}
// Test
module.exports = {
computesAnnualProfit: function () {
repo.saveTransactions([
{year: 2016, month: 3, day: 14, price: 55.44, cost: 80.30},
{year: 2016, month: 6, day: 20, price: 9.33, cost: 4.00},
{year: 2016, month: 12, day: 31, price: 112.48, cost: 100.24},
// Bad year:
{year: 2015, month: 3, day: 14, price: 999, cost: 0}
])
var result = annualProfit(2016)
assert.equal(result, -8)
},
computesMonthlyProfit: function () {
repo.saveTransactions([
{year: 2016, month: 5, day: 1, price: 108.99, cost: 70.45},
{year: 2016, month: 5, day: 15, price: 208.13, cost: 133.55},
{year: 2016, month: 5, day: 31, price: 90.00, cost: 80.03},
// Bad month:
{year: 2016, month: 6, day: 14, price: 999, cost: 0}
])
var result = monthlyProfit(2016, 5)
assert.equal(result, 124)
},
computesDailyProfit: function () {
repo.saveTransactions([
{year: 2016, month: 5, day: 12, price: 19.44, cost: 18.11},
{year: 2016, month: 5, day: 12, price: 21.40, cost: 22.01},
{year: 2016, month: 5, day: 12, price: 998.10, cost: 907.20},
// Bad day:
{year: 2016, month: 5, day: 1, price: 999, cost: 0}
])
var result = dailyProfit(2016, 5, 12)
assert.equal(result, 91)
},
computesTransactionProfit: function () {
var transaction = {price: 33.22, cost: 20.11}
var result = transactionProfit(transaction)
assert.equal(result, 13)
},
afterEach: function () {
repo.reset()
}
}
// Fake production implementations to simplify example test of subject
var repo = {
__transactions: [],
reset: function () {
repo.__transactions = []
},
saveTransactions: function (transactions) {
repo.__transactions.push.apply(repo.__transactions, transactions)
},
find: function (criteria) {
return _.filter(repo.__transactions, criteria)
}
}
References:
Quality attributes
- Code Example
- Cause and Effect
- Frequency
- Refactoring