Confidential & Proprietary
www.leadingedje.com
A Lifecycle of
Code Under Test
Bob Fornal
Twitter: @rfornal
https://dev.to/rfornal
Confidential & Proprietary
www.leadingedje.com
Confidential & Proprietary
www.leadingedje.com
This Talk
Confidential & Proprietary
www.leadingedje.com
Confidential & Proprietary
www.leadingedje.com
life cycle noun
Definition of life cycle
1. the series of stages in form and functional activity through which an
organism passes between successive recurrences of a specified
primary stage
2. LIFE HISTORY sense 2
3. a series of stages through which something (such as an individual,
culture, or manufactured product) passes during its lifetime
https://www.merriam-webster.com/dictionary/life%20cycle
Confidential & Proprietary
www.leadingedje.com
Confidential & Proprietary
www.leadingedje.com
Software Development Life Cycle
https://stackoverflow.com/questions/876089/who-wrote-this-programing-saying-always-code-as-if-the-guy-who-ends-up-maintai
https://producttribe.com/project-management/sdlc-guide
Always code as if the guy who
ends up maintaining your code
will be a violent psychopath who
knows where you live.
- John Woods
Confidential & Proprietary
www.leadingedje.com
Confidential & Proprietary
www.leadingedje.com
The Testing Dorito ...
https://twitter.com/kentcdodds/status/960723172591992832
Confidential & Proprietary
www.leadingedje.com
Confidential & Proprietary
www.leadingedje.com
Testing Forms (Unit / Integration / QA)
Confidential & Proprietary
www.leadingedje.com
Confidential & Proprietary
www.leadingedje.com
Overview
1. Define Inputs and Outputs
2. Initial Testing (coverage)
a. All Branches (paths)
b. Positive Testing
c. Negative Testing
3. Handling Bugs (coverage)
4. Refactoring
5. Abstraction
6. … Future Work (how are tests affected?)
a. Black Box Testing
b. White Box Testing
7. Handling Legacy Monoliths
Programming is like sex: one
mistake and you’re providing
support for a lifetime.
- Michael Sinz
Redesign
Confidential & Proprietary
www.leadingedje.com
Confidential & Proprietary
www.leadingedje.com
Redesign
Factors …
● Age of old version
● New Framework / Tooling
Which tools / tests are still valid?
Confidential & Proprietary
www.leadingedje.com
Confidential & Proprietary
www.leadingedje.com
An Overly Complicated Function To Add Two Strings
function overlyComplicated(a, b, len) {
var sum = “”;
if (len < 1) {
return “”;
}
for (var i = 0; i < a.length; i++) {
sum = sum + a[i];
}
for (var i = 0; i < b.length; i++) {
sum = sum + b[i];
}
// ”INJECTED” BUG HERE
if (len === 2 || len === 4 || len === 6) {
return “unexpected”;
}
return sum.substr(0, len);
}
var oC = overlyComplicated;
Confidential & Proprietary
www.leadingedje.com
Confidential & Proprietary
www.leadingedje.com
function overlyComplicated(a, b, len) {
var sum = “”;
if (len < 1) {
return “”;
}
for (var i = 0; i < a.length; i++) {
sum = sum + a[i];
}
for (var i = 0; i < b.length; i++) {
sum = sum + b[i];
}
// ”INJECTED” BUG HERE
if (len === 2 || len === 4 || len === 6) {
return “unexpected”;
}
return sum.substr(0, len);
}
var oC = overlyComplicated;
Inputs
● a: string of some length.
● b: string of some length.
● len: number (integer) of characters of the combined to
return.
Outputs
● string of “len” characters.
Examples
● (“abc”, “def”, 0) returns “”
● (“abc”, “def”, 1) returns “a”
● (“abc”, “def”, 3) returns “abc”
● (“abc”, “def”, 5) returns “abcde”
Define Inputs and Outputs
Confidential & Proprietary
www.leadingedje.com
Confidential & Proprietary
www.leadingedje.com
function overlyComplicated(a, b, len) {
var sum = “”;
if (len < 1) {
return “”;
}
for (var i = 0; i < a.length; i++) {
sum = sum + a[i];
}
for (var i = 0; i < b.length; i++) {
sum = sum + b[i];
}
// ”INJECTED” BUG HERE
if (len === 2 || len === 4 || len === 6) {
return “unexpected”;
}
return sum.substr(0, len);
}
var oC = overlyComplicated;
All Branches (paths)
● No Branches
Positive Testing
● expect(oC(“abc”, “def”, 1)).toEqual(“a”);
● expect(oC(“abc”, “def”, 3)).toEqual(“abc”);
● expect(oC(“abc”, “def”, 5)).toEqual(“abcde”);
Negative Testing
● expect(oC(“abc”, “def”, 0)).toEqual(“”);
● expect(oC(“abc”, “def”, -1)).toEqual(“”);
Initial Testing (coverage)
Confidential & Proprietary
www.leadingedje.com
Confidential & Proprietary
www.leadingedje.com
function overlyComplicated(a, b, len) {
var sum = “”;
if (len < 1) {
return “”;
}
for (var i = 0; i < a.length; i++) {
sum = sum + a[i];
}
for (var i = 0; i < b.length; i++) {
sum = sum + b[i];
}
// ”INJECTED” BUG HERE
if (len === 2 || len === 4 || len === 6) {
return “unexpected”;
}
return sum.substr(0, len);
}
var oC = overlyComplicated;
Repeating The Bug In Test Form ...
expect(oC(“abc”, “def”, 2)).toEqual(“ab”);
● expect “unexpected” to equal “ab”.
expect(oC(“abc”, “def”, 4)).toEqual(“abcd”);
● expect “unexpected” to equal “abcd”.
expect(oC(“abc”, “def”, 6)).toEqual(“abcdef”);
● expect “unexpected” to equal “abcdef”.
Handling Bugs (coverage)
Confidential & Proprietary
www.leadingedje.com
Confidential & Proprietary
www.leadingedje.com
function overlyComplicated(a, b, len) {
var sum = “”;
if (len < 1) {
return “”;
}
for (var i = 0; i < a.length; i++) {
sum = sum + a[i];
}
for (var i = 0; i < b.length; i++) {
sum = sum + b[i];
}
// ”INJECTED” BUG HERE
// if (len === 2 || len === 4 || len === 6) {
// return “unexpected”;
// }
return sum.substr(0, len);
}
var oC = overlyComplicated;
After Fixing The Bug
● expect(oC(“abc”, “def”, 2)).toEqual(“ab”);
● expect(oC(“abc”, “def”, 4)).toEqual(“abcd”);
● expect(oC(“abc”, “def”, 6)).toEqual(“abcdef”);
Handling Bugs (coverage)
Confidential & Proprietary
www.leadingedje.com
Confidential & Proprietary
www.leadingedje.com
function overlyComplicated(a, b, len) {
var sum = “”;
if (len < 1) {
return “”;
}
sum = a + b;
sum = sum.substr(0, len);
return sum;
// for (var i = 0; i < a.length; i++) {
// sum = sum + a[i];
// }
// for (var i = 0; i < b.length; i++) {
// sum = sum + b[i];
// }
// return sum.substr(0, len);
}
var oC = overlyComplicated;
After Refactor
... Previous Tests Should Still Pass
Positive Testing
● expect(oCAS(“abc”, “def”, 1)).toEqual(“a”);
● expect(oCAS(“abc”, “def”, 3)).toEqual(“abc”);
● expect(oCAS(“abc”, “def”, 5)).toEqual(“abcde”);
Negative Testing
● expect(oCAS(“abc”, “def”, 0)).toEqual(“”);
● expect(oCAS(“abc”, “def”, -1)).toEqual(“”);
Bug Testing
● expect(oCAS(“abc”, “def”, 2)).toEqual(“ab”);
● expect(oCAS(“abc”, “def”, 4)).toEqual(“abcd”);
● expect(oCAS(“abc”, “def”, 6)).toEqual(“abcdef”);
Refactoring
Confidential & Proprietary
www.leadingedje.com
Confidential & Proprietary
www.leadingedje.com
function getSum(a, b) {
return a + b;
}
function overlyComplicated(sumFn, a, b, len) {
var sum = “”;
if (len < 1) {
return “”;
}
sum = sumFn(a, b).substr(0, len);
// sum = a + b;
// sum = sum.substr(0, len);
return sum;
}
function oC(a, b, len) {
return overlyComplicated(getSum, a, b, len);
}
After Abstraction
... Previous Tests Should Still Pass
... Should Add Tests For Abstracted Functionality
... Have Flexibility When Testing Injected Code
Positive, Negative, and Bug Testing
● All Pass
Abstraction
● expect(getSum(“abc”, “dev”)).toEqual(“abcdef”);
Abstraction
Confidential & Proprietary
www.leadingedje.com
Confidential & Proprietary
www.leadingedje.com
var global = {};
function getSum(a, b) {
return a + b;
}
function overlyComplicated(sumFn, a, b, len) {
var sum = “”;
if (len < 1) {
return “”;
}
sum = sumFn(a, b).substr(0, len);
global.sum = sum;
return sum;
}
function oC(a, b, len) {
return overlyComplicated(getSum, a, b, len);
}
How Are Tests Affected?
● Per Black-Box Testing, no test should fail (purely
examining inputs to outputs).
● Per White-Box Testing, tests should be written to cover
the new code.
Future Work Tests
... given
● oC(“abc”, “def”, 1);
... then
● expect(global.sum).toEqual(“a”);
Handling A/B Tests
● Branching considerations
Future Work
Confidential & Proprietary
www.leadingedje.com
Confidential & Proprietary
www.leadingedje.com
Handling Legacy Monoliths
Issues
● Code that is not covered by tests
● Existing tests that are not dependable
Resolutions
● Push testing coverage to a higher level where quick implementation can cover more code;
this allows lower code to be refactored or redesigned while keeping functionality.
● Higher test coverage can be removed (or not run during tests) once testing at lower levels
is complete.
Confidential & Proprietary
www.leadingedje.com
Confidential & Proprietary
www.leadingedje.com
Overview
1. Define Inputs and Outputs
2. Initial Testing (coverage)
a. All Branches (paths)
b. Positive Testing
c. Negative Testing
3. Handling Bugs (coverage)
4. Refactoring
5. Abstraction
6. … Future Work (how are tests affected?)
a. Black Box Testing
b. White Box Testing
7. Handling Legacy Monoliths
Redesign
Confidential & Proprietary
www.leadingedje.com
Confidential & Proprietary
www.leadingedje.com
Questions ...

A Lifecycle Of Code Under Test by Robert Fornal

  • 1.
    Confidential & Proprietary www.leadingedje.com ALifecycle of Code Under Test Bob Fornal Twitter: @rfornal https://dev.to/rfornal
  • 2.
    Confidential & Proprietary www.leadingedje.com Confidential& Proprietary www.leadingedje.com This Talk
  • 3.
    Confidential & Proprietary www.leadingedje.com Confidential& Proprietary www.leadingedje.com life cycle noun Definition of life cycle 1. the series of stages in form and functional activity through which an organism passes between successive recurrences of a specified primary stage 2. LIFE HISTORY sense 2 3. a series of stages through which something (such as an individual, culture, or manufactured product) passes during its lifetime https://www.merriam-webster.com/dictionary/life%20cycle
  • 4.
    Confidential & Proprietary www.leadingedje.com Confidential& Proprietary www.leadingedje.com Software Development Life Cycle https://stackoverflow.com/questions/876089/who-wrote-this-programing-saying-always-code-as-if-the-guy-who-ends-up-maintai https://producttribe.com/project-management/sdlc-guide Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. - John Woods
  • 5.
    Confidential & Proprietary www.leadingedje.com Confidential& Proprietary www.leadingedje.com The Testing Dorito ... https://twitter.com/kentcdodds/status/960723172591992832
  • 6.
    Confidential & Proprietary www.leadingedje.com Confidential& Proprietary www.leadingedje.com Testing Forms (Unit / Integration / QA)
  • 7.
    Confidential & Proprietary www.leadingedje.com Confidential& Proprietary www.leadingedje.com Overview 1. Define Inputs and Outputs 2. Initial Testing (coverage) a. All Branches (paths) b. Positive Testing c. Negative Testing 3. Handling Bugs (coverage) 4. Refactoring 5. Abstraction 6. … Future Work (how are tests affected?) a. Black Box Testing b. White Box Testing 7. Handling Legacy Monoliths Programming is like sex: one mistake and you’re providing support for a lifetime. - Michael Sinz Redesign
  • 8.
    Confidential & Proprietary www.leadingedje.com Confidential& Proprietary www.leadingedje.com Redesign Factors … ● Age of old version ● New Framework / Tooling Which tools / tests are still valid?
  • 9.
    Confidential & Proprietary www.leadingedje.com Confidential& Proprietary www.leadingedje.com An Overly Complicated Function To Add Two Strings function overlyComplicated(a, b, len) { var sum = “”; if (len < 1) { return “”; } for (var i = 0; i < a.length; i++) { sum = sum + a[i]; } for (var i = 0; i < b.length; i++) { sum = sum + b[i]; } // ”INJECTED” BUG HERE if (len === 2 || len === 4 || len === 6) { return “unexpected”; } return sum.substr(0, len); } var oC = overlyComplicated;
  • 10.
    Confidential & Proprietary www.leadingedje.com Confidential& Proprietary www.leadingedje.com function overlyComplicated(a, b, len) { var sum = “”; if (len < 1) { return “”; } for (var i = 0; i < a.length; i++) { sum = sum + a[i]; } for (var i = 0; i < b.length; i++) { sum = sum + b[i]; } // ”INJECTED” BUG HERE if (len === 2 || len === 4 || len === 6) { return “unexpected”; } return sum.substr(0, len); } var oC = overlyComplicated; Inputs ● a: string of some length. ● b: string of some length. ● len: number (integer) of characters of the combined to return. Outputs ● string of “len” characters. Examples ● (“abc”, “def”, 0) returns “” ● (“abc”, “def”, 1) returns “a” ● (“abc”, “def”, 3) returns “abc” ● (“abc”, “def”, 5) returns “abcde” Define Inputs and Outputs
  • 11.
    Confidential & Proprietary www.leadingedje.com Confidential& Proprietary www.leadingedje.com function overlyComplicated(a, b, len) { var sum = “”; if (len < 1) { return “”; } for (var i = 0; i < a.length; i++) { sum = sum + a[i]; } for (var i = 0; i < b.length; i++) { sum = sum + b[i]; } // ”INJECTED” BUG HERE if (len === 2 || len === 4 || len === 6) { return “unexpected”; } return sum.substr(0, len); } var oC = overlyComplicated; All Branches (paths) ● No Branches Positive Testing ● expect(oC(“abc”, “def”, 1)).toEqual(“a”); ● expect(oC(“abc”, “def”, 3)).toEqual(“abc”); ● expect(oC(“abc”, “def”, 5)).toEqual(“abcde”); Negative Testing ● expect(oC(“abc”, “def”, 0)).toEqual(“”); ● expect(oC(“abc”, “def”, -1)).toEqual(“”); Initial Testing (coverage)
  • 12.
    Confidential & Proprietary www.leadingedje.com Confidential& Proprietary www.leadingedje.com function overlyComplicated(a, b, len) { var sum = “”; if (len < 1) { return “”; } for (var i = 0; i < a.length; i++) { sum = sum + a[i]; } for (var i = 0; i < b.length; i++) { sum = sum + b[i]; } // ”INJECTED” BUG HERE if (len === 2 || len === 4 || len === 6) { return “unexpected”; } return sum.substr(0, len); } var oC = overlyComplicated; Repeating The Bug In Test Form ... expect(oC(“abc”, “def”, 2)).toEqual(“ab”); ● expect “unexpected” to equal “ab”. expect(oC(“abc”, “def”, 4)).toEqual(“abcd”); ● expect “unexpected” to equal “abcd”. expect(oC(“abc”, “def”, 6)).toEqual(“abcdef”); ● expect “unexpected” to equal “abcdef”. Handling Bugs (coverage)
  • 13.
    Confidential & Proprietary www.leadingedje.com Confidential& Proprietary www.leadingedje.com function overlyComplicated(a, b, len) { var sum = “”; if (len < 1) { return “”; } for (var i = 0; i < a.length; i++) { sum = sum + a[i]; } for (var i = 0; i < b.length; i++) { sum = sum + b[i]; } // ”INJECTED” BUG HERE // if (len === 2 || len === 4 || len === 6) { // return “unexpected”; // } return sum.substr(0, len); } var oC = overlyComplicated; After Fixing The Bug ● expect(oC(“abc”, “def”, 2)).toEqual(“ab”); ● expect(oC(“abc”, “def”, 4)).toEqual(“abcd”); ● expect(oC(“abc”, “def”, 6)).toEqual(“abcdef”); Handling Bugs (coverage)
  • 14.
    Confidential & Proprietary www.leadingedje.com Confidential& Proprietary www.leadingedje.com function overlyComplicated(a, b, len) { var sum = “”; if (len < 1) { return “”; } sum = a + b; sum = sum.substr(0, len); return sum; // for (var i = 0; i < a.length; i++) { // sum = sum + a[i]; // } // for (var i = 0; i < b.length; i++) { // sum = sum + b[i]; // } // return sum.substr(0, len); } var oC = overlyComplicated; After Refactor ... Previous Tests Should Still Pass Positive Testing ● expect(oCAS(“abc”, “def”, 1)).toEqual(“a”); ● expect(oCAS(“abc”, “def”, 3)).toEqual(“abc”); ● expect(oCAS(“abc”, “def”, 5)).toEqual(“abcde”); Negative Testing ● expect(oCAS(“abc”, “def”, 0)).toEqual(“”); ● expect(oCAS(“abc”, “def”, -1)).toEqual(“”); Bug Testing ● expect(oCAS(“abc”, “def”, 2)).toEqual(“ab”); ● expect(oCAS(“abc”, “def”, 4)).toEqual(“abcd”); ● expect(oCAS(“abc”, “def”, 6)).toEqual(“abcdef”); Refactoring
  • 15.
    Confidential & Proprietary www.leadingedje.com Confidential& Proprietary www.leadingedje.com function getSum(a, b) { return a + b; } function overlyComplicated(sumFn, a, b, len) { var sum = “”; if (len < 1) { return “”; } sum = sumFn(a, b).substr(0, len); // sum = a + b; // sum = sum.substr(0, len); return sum; } function oC(a, b, len) { return overlyComplicated(getSum, a, b, len); } After Abstraction ... Previous Tests Should Still Pass ... Should Add Tests For Abstracted Functionality ... Have Flexibility When Testing Injected Code Positive, Negative, and Bug Testing ● All Pass Abstraction ● expect(getSum(“abc”, “dev”)).toEqual(“abcdef”); Abstraction
  • 16.
    Confidential & Proprietary www.leadingedje.com Confidential& Proprietary www.leadingedje.com var global = {}; function getSum(a, b) { return a + b; } function overlyComplicated(sumFn, a, b, len) { var sum = “”; if (len < 1) { return “”; } sum = sumFn(a, b).substr(0, len); global.sum = sum; return sum; } function oC(a, b, len) { return overlyComplicated(getSum, a, b, len); } How Are Tests Affected? ● Per Black-Box Testing, no test should fail (purely examining inputs to outputs). ● Per White-Box Testing, tests should be written to cover the new code. Future Work Tests ... given ● oC(“abc”, “def”, 1); ... then ● expect(global.sum).toEqual(“a”); Handling A/B Tests ● Branching considerations Future Work
  • 17.
    Confidential & Proprietary www.leadingedje.com Confidential& Proprietary www.leadingedje.com Handling Legacy Monoliths Issues ● Code that is not covered by tests ● Existing tests that are not dependable Resolutions ● Push testing coverage to a higher level where quick implementation can cover more code; this allows lower code to be refactored or redesigned while keeping functionality. ● Higher test coverage can be removed (or not run during tests) once testing at lower levels is complete.
  • 18.
    Confidential & Proprietary www.leadingedje.com Confidential& Proprietary www.leadingedje.com Overview 1. Define Inputs and Outputs 2. Initial Testing (coverage) a. All Branches (paths) b. Positive Testing c. Negative Testing 3. Handling Bugs (coverage) 4. Refactoring 5. Abstraction 6. … Future Work (how are tests affected?) a. Black Box Testing b. White Box Testing 7. Handling Legacy Monoliths Redesign
  • 19.
    Confidential & Proprietary www.leadingedje.com Confidential& Proprietary www.leadingedje.com Questions ...