简体   繁体   中英

TDD: How to unit test functions that rely on other functions?

Suppose I have a function A that takes in a string. Function A calls function B from the same file, which takes that string and modifies it. Function A then returns a value based on the modified output string from function B.

How should I best write unit tests for function A given that it depends on the output from B? If my understanding is correct, unit tests should test the logic of a function independent from its dependencies. Following this line of thought, I was thinking of mocking function B and its output so that the test for A wouldn't necessarily fail if function B wasn't working. Is this line of thought correct? Example case below:

const functionA = (string, table) => {
  const hex = functionB(string);

  return table[hex];
}

const functionB = (string) => {
  //some kind of hexing function here

  return hexed string
}

The usual answer is to just write your tests for A without mocking B.

The explanation being that "testing a function independent of its dependencies" wasn't actually a priority. Beck, Jeffries, et al used the spelling "Unit Test", but they didn't mean that in the usual sense. Later on, they tried "developer test" and "programmer test" as labels, but by then habit had set in and the damage had been done.

One way to see that this must be true is to consider writing tests for a "unit", and then later performing a refactoring that extracts another method -- the original tests still work, even though the test subject is no longer a single "unit".


There are, of course, cases where you will want to introduce a substitute implementation for B when testing A

  • the real B makes A expensive to test
  • the behaviors of the real B are unstable, making the A tests expensive to maintain
  • the design you are trying to drive is the protocol between A and B

(Your concern appears to be the middle one).


Another possible approach is to extract another function from A

const functionA = (string, table) => {
  return functionC(string, table, functionB);
}

const functionB = (string) => {
  //some kind of hexing function here

  return hexed string
}

const functionC = (string, table, fn) {
  const hex = fn(string);
  return table[hex];
}

Here, functionA is "so simple there are obviously no deficiencies"; we've moved all of the risk to functionC. The "stub" / "test-double" that we want to use as a substitute for functionB is just another argument.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM