title: How would I unit test a method with side effects?
body: <p>Given the following implementation:</p>
  
  <pre><code>class Foo {
      public function helper() {
          // Does something with external side effects, like updating
          // a database or altering the file system.
      }
  
      public function bar() {
          if ($this-&gt;helper() === FALSE) {
              throw new Exception(/* ... */);
          }
      }
  }
  </code></pre>
  
  <p>How would I unit test <code>Foo::bar()</code> without incurring the side effects of <code>Foo::helper()</code> during testing?</p>
  
  <p>I know I can mock <code>Foo</code> and stub <code>Foo::helper()</code>:</p>
  
  <pre><code>public function testGoodBar() {
      $mock = $this-&gt;getMock('Foo', array('helper'));
      $this-&gt;expects($this-&gt;once())
          -&gt;method('helper')
          -&gt;will($this-&gt;returnValue(TRUE));
  
      $this-&gt;assertTrue($mock-&gt;bar());
  }
  </code></pre>
  
  <p>...but this leaves the test wide open for code changes that introduce other methods which may have side effects.  Then if the test is run again without being updated, the test itself will have permanent side effects.</p>
  
  <p>I could also mock <code>Foo</code>, such that all its methods get mocked and won't produce side effects:</p>
  
  <pre><code>public function testGoodBar() {
      $mock = $this-&gt;getMock('Foo');
      $this-&gt;expects($this-&gt;once())
          -&gt;method('helper')
          -&gt;will($this-&gt;returnValue(TRUE));
  
      $this-&gt;assertTrue($mock-&gt;bar());
  }
  </code></pre>
  
  <p>...but then even <code>Foo::bar()</code> gets mocked, which is bad, since that's the method we want to test.</p>
  
  <p>The only solution I could come up with is explicitly mocking all methods <em>except</em> the one under test:</p>
  
  <pre><code>public function testGoodBar() {
      $mock = $this-&gt;getMock('Foo', array_diff(
          get_class_methods('Foo'),
          'bar'
      ));
  
      $this-&gt;expects($this-&gt;once())
          -&gt;method('helper')
          -&gt;will($this-&gt;returnValue(TRUE));
  
      $this-&gt;assertTrue($mock-&gt;bar());
  }
  </code></pre>
  
  <p>...but this seems kludgy, and I feel like I'm missing something obvious.</p>