title: Should I unit test *what* or *how* for composite functions?
body: <p>I have functions <code>f</code> and <code>g</code>, which already have a collection of unit tests ensuring that their behavior is correct for some known inputs-output pairs (plus exception handling, etc).</p>
  
  <p>Now I'm creating the function <code>h()</code>, as follows:</p>
  
  <pre><code>def h(x):
      return f(x) + g(2*x)
  </code></pre>
  
  <p>What's a good approach for unit testing this function? Would this change if <code>h()</code> was substantially more complex?</p>
  
  <hr>
  
  <p><em>My thoughts so far:</em> </p>
  
  <p>I see two possibilities for testing <code>h()</code>.</p>
  
  <h3>1. Testing if <code>h()</code> is doing the correct "plumbing"</h3>
  
  <p>Mock out <code>f()</code> so that it returns <code>y_0</code> when called with input <code>x_0</code>; mock <code>g()</code> so that it returns <code>z_0</code> when called with input <code>2*x_0</code>. Then check that calling <code>h(x_0)</code> returns <code>y_0+z_0</code>.</p>
  
  <p><em>Advantages</em>:</p>
  
  <ul>
  <li>Very simple to implement the test.</li>
  <li>Can quickly find bugs where I incorrectly connected the outputs of <code>f</code> and <code>g</code>, or where I called them with wrong arguments (say, calling <code>g(x)</code> instead of <code>g(2*x)</code> in <code>h()</code>).</li>
  </ul>
  
  <p><em>Disadvantages</em>:</p>
  
  <ul>
  <li>This is testing <em>how</em>, not <em>what</em> <code>h()</code> should do. If later I want to refactor <code>h()</code>, then I'll probably need to rewrite these types of tests.</li>
  <li>If the plumbing specified by the test does not produce the intended high-level behavior for <code>h()</code>, then these tests won't catch this error. For example, maybe the correct plumbing was supposed to be <code>f(-x) + g(2*x)</code>, and I made it wrong both in the function definition and in the test definition.</li>
  </ul>
  
  <h3>2. Testing <strong>what</strong> <code>h()</code> should do</h3>
  
  <p>Let's say that the purpose of <code>h()</code> is to compute the sum of primes below the given argument. In this case, a natural test suite for <code>h()</code> would involve testing it with known input-output pairs. Something that makes sure that, for instance, <code>h(1)=2</code>, <code>h(2)=5</code>, <code>h(5)=28</code>, etc, not caring about <strong>how</strong> <code>h()</code> is computing these numbers.</p>
  
  <p><em>Advantages</em>: </p>
  
  <ul>
  <li>This type of test checks that <code>h()</code> is indeed following its intended high-level behavior. Any plumbing mistakes that alter this will be caught.</li>
  <li>Refactoring <code>h()</code> will probably not necessitate changing the test suite, and will even be easier, since the tests help us guarantee that the behavior of the function doesn't change.</li>
  </ul>
  
  <p><em>Disadvantages</em>:</p>
  
  <ul>
  <li>In this simple example it's easy to produce such pairs because the mapping that <code>h()</code> performs is not very complicated (just sum the <code>n</code> first primes). However, for a very complicated <code>h()</code>, my only option for producing such pairs might be me to come up with an input <code>x</code> and compute the correct output by hand. This doesn't seem reasonable if <code>h</code> is very complicated.</li>
  <li>Since coming up with known input-output pairs requires me to compute what <code>f()</code> and <code>g()</code> will produce given a certain input, there will probably be some duplication of effort, since I already spent some time doing that when creating the unit tests for these functions.</li>
  </ul>
  
  <hr>
  
  <p><em>Related question</em>: <a href="https://stackoverflow.com/questions/45654729/unit-testing-composite-functions">Unit testing composite functions</a>.</p>
  
  <p>This question is at first glance very similar to mine. However, the two most voted answers present completely different approaches to the problem (the two approaches I mentioned above). My question is an attempt in clarifying the pros/cons of each approach (and perhaps learn other approaches), and potentially establish which is best overall. If no approach is best in all cases, I would like to understand in which cases one should use each of them.</p>