Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing pure function on union type which delegates to other pure functions

Suppose you have function which takes a union type and then narrows the type and delegate to one of two other pure functions.

function foo(arg: string|number) {
    if (typeof arg === 'string') {
        return fnForString(arg)
    } else {
        return fnForNumber(arg)
    }
}

Assume that fnForString() and fnForNumber() are also pure functions, and they have already themselves been tested.

How should one go about testing foo()?

  • Should you treat the fact that it delegates to fnForString() and fnForNumber() as an implementation detail, and essentially duplicate the tests for each of them when writing the tests for foo()? Is this repetition acceptable?
  • Should you write tests which "know" that foo() delegate to fnForString() and fnForNumber() e.g. by mocking them out and checking that it delegates to them?
like image 602
samfrances Avatar asked Oct 11 '19 08:10

samfrances


People also ask

How do you know if a function is pure or not?

A pure function is a function where the return value is only determined by its input values, without observable side effects. When a function performs any other “action”, apart from calculating its return value, the function is impure. Single impure function would contaminate any function that calls it.

Which of the following rules are correct for pure functions?

A function must pass two tests to be considered “pure”: Same inputs always return same outputs. No side-effects.

What is the other name of pure function?

The only result of calling a pure function is the return value. Examples of pure functions are strlen(), pow(), sqrt() etc. Examples of impure functions are printf(), rand(), time(), etc.


1 Answers

The best solution would be just testing for foo.

fnForString and fnForNumber are an implementation detail that you may change in the future without necessarily changing the behaviour of foo. If that happens your tests may break with no reason, this kind of problem makes your test too expansive and useless.

Your interface just needs foo, just test for it.

If you have to test for fnForString and fnForNumber keep this kind of test apart from your public interface tests.

This is my interpretation of the following principle stated by Kent Beck

Programmer tests should be sensitive to behaviour changes and insensitive to structure changes. If the program’s behavior is stable from an observer’s perspective, no tests should change.

like image 104
Giuseppe Schembri Avatar answered Sep 27 '22 17:09

Giuseppe Schembri