<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
  <channel>
    <title>Blog entries tagged testing :: mwop.net</title>
    <description>Blog entries tagged testing :: mwop.net</description>
    <pubDate>Thu, 21 Aug 2014 14:30:00 -0500</pubDate>
    <generator>Laminas_Feed_Writer 2 (https://getlaminas.org)</generator>
    <link>https://mwop.net/blog/tag/testing</link>
    <atom:link rel="self" type="application/rss+xml" href="https://mwop.net/blog/tag/testing/rss.xml"/>
    <item>
      <title>Testing Code That Emits Output</title>
      <pubDate>Thu, 21 Aug 2014 14:30:00 -0500</pubDate>
      <link>https://mwop.net/blog/2014-08-11-testing-output-generating-code.html</link>
      <guid>https://mwop.net/blog/2014-08-11-testing-output-generating-code.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>Here's the scenario: you have code that will emit headers and content, for
instance, a front controller. How do you test this?</p>
<p>The answer is remarkably simple, but non-obvious: namespaces.</p>


<h2>Prerequisites</h2>
<p>For this approach to work, the assumptions are:</p>
<ul>
<li>Your code emitting headers and output lives in a namespace other than the
global namespace.</li>
</ul>
<p>That's it. Considering that most PHP code you grab anymore does this, and most
coding standards you run across will require this, it's a safe bet that you're
already ready. If you're not, go refactor your code now, before continuing;
you'll thank me later.</p>
<h2>The technique</h2>
<p>PHP introduced namespaces in PHP 5.3. Namespaces cover classes, as most of us
are well aware, but they also cover constants and functions — a fact often
overlooked, as before 5.6 (releasing next week!), you cannot import them via
use statements!</p>
<p>That does not mean they cannot be defined and used, however — it just means
that you need to manually import them, typically via a <code>require</code> or <code>require_once</code>
statement. These are usually anathema in libraries, but for testing, they work
just fine.</p>
<p>Here's an approach I took recently. I created a file that lives — this is the
important bit, so pay attention — <em>in the same namespace as the code emitting
headers and output</em>. This file defines several functions that live in the
global (aka PHP's built-in) namespace, and an accumulator static object I can
then use in my tests for assertions. Here's what it looks like:</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-keyword">namespace</span> <span class="hljs-title">Some</span>\<span class="hljs-title">Project</span>;

<span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Output</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> $headers = <span class="hljs-keyword">array</span>();
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> $body;

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">reset</span><span class="hljs-params">()</span>
    </span>{
        <span class="hljs-keyword">self</span>::$headers = <span class="hljs-keyword">array</span>();
        <span class="hljs-keyword">self</span>::$body = <span class="hljs-keyword">null</span>;
    }
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">headers_sent</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">header</span><span class="hljs-params">($value)</span>
</span>{
    Output::$headers[] = $value;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">printf</span><span class="hljs-params">($text)</span>
</span>{
    Output::$body .= $text;
}
</code></pre>
<p>A few notes:</p>
<ul>
<li><code>headers_sent()</code> always returns false here, as most emitters test for a boolean true value and bail early when that occurs.</li>
<li>I used <code>printf()</code> here, as echo cannot be overridden due to being a PHP
language construct and not an actual function. As such, if you use this
technique, you will have to likely alter your emitter to call <code>printf()</code>
instead of echo. The benefits, however, are worth it.</li>
<li>I marked Output abstract, to prevent instantiation; it should only be used
statically.</li>
</ul>
<p>I place the above file within my test suite, usually under a <code>TestAsset</code>
directory adjacent to the test itself; since it contains functions, I'll name
the file <code>Functions.php</code> as well. This combination typically will prevent it
from being autoloaded in any way, as the test directory will often not have
autoloading defined, or will be under a separate namespace.</p>
<p>Inside your PHPUnit test suite, then, you would do the following:</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-keyword">namespace</span> <span class="hljs-title">SomeTest</span>\<span class="hljs-title">Project</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">PHPUnit_Framework_TestCase</span> <span class="hljs-title">as</span> <span class="hljs-title">TestCase</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Some</span>\<span class="hljs-title">Project</span>\<span class="hljs-title">FrontController</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Some</span>\<span class="hljs-title">Project</span>\<span class="hljs-title">Output</span>;                 <span class="hljs-comment">// &lt;-- our Output class from above</span>
<span class="hljs-keyword">require_once</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">'/TestAsset/Functions.php'</span>; <span class="hljs-comment">// &lt;-- get our functions</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FrontControllerTest</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">TestCase</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setUp</span><span class="hljs-params">()</span>
    </span>{
        Output::reset();
        <span class="hljs-comment">/* ... */</span>
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">tearDown</span><span class="hljs-params">()</span>
    </span>{
        Output::reset();
        <span class="hljs-comment">/* ... */</span>
    }
}
</code></pre>
<p>From here, you test as normal — but when you invoke methods that will cause
headers or content to emit, you can now test to see what those contain:</p>
<pre><code class="language-php hljs php" data-lang="php">    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">testEmitsExpectedHeadersAndContent</span><span class="hljs-params">()</span>
    </span>{
        <span class="hljs-comment">/* ... */</span>

        <span class="hljs-keyword">$this</span>-&gt;assertContains(<span class="hljs-string">'Content-Type: application/json'</span>, Output::$headers);
        $json = Output::$body;
        $data = json_decode($json, <span class="hljs-keyword">true</span>);
        <span class="hljs-keyword">$this</span>-&gt;assertArrayHasKey(<span class="hljs-string">'foo'</span>, $data);
        <span class="hljs-keyword">$this</span>-&gt;assertEquals(<span class="hljs-string">'bar'</span>, $data[<span class="hljs-string">'foo'</span>]);
    }
</code></pre>
<h2>How it works</h2>
<p>Why does this work?</p>
<p>PHP performs some magic when it resolves functions. With classes, it looks for
a matching class either in the current namespace, or one that was imported (and
potentially aliased); if a match is not found, it stops, and raises an error.
With functions, however, it looks first in the current namespace, and if it
isn't found, then looks in the global namespace. This last part is key — it
means that if you redefine a function in the current namespace, it will be used
in lieu of the original function defined by PHP. This also means that any code
operating in the same namespace as the function — even if defined in another
file — will use that function.</p>
<p>This technique just leverages this fact.</p>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&u=79dd2ea1d4d8855944715d09ee4c86215027fa80&s=140" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/2014-08-11-testing-output-generating-code.html">Testing Code That Emits Output</a> was originally
    published <time class="dt-published" datetime="2014-08-21T14:30:00-05:00">21 August 2014</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>Setting up your Zend_Test test suites</title>
      <pubDate>Sat, 13 Sep 2008 09:37:40 -0500</pubDate>
      <link>https://mwop.net/blog/190-Setting-up-your-Zend_Test-test-suites.html</link>
      <guid>https://mwop.net/blog/190-Setting-up-your-Zend_Test-test-suites.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>Now that <a href="http://framework.zend.com/manual/en/zend.test.html">Zend_Test</a> has
shipped, developers are of course asking, &quot;How do I setup my test suite?&quot;
Fortunately, after some discussion with my colleagues and a little
experimenting on my one, I can answer that now.</p>


<p><a href="http://phpunit.de">PHPUnit</a> offers a variety of methods for setting up test
suites, some trivial and some complex. The Zend Framework test suite, for
instance, goes for a more complex route, adding component-level suites that
require a fair amount of initial setup, but which allow us fairly fine-grained
control.</p>
<p>However, testing and test automation should be easy and the complex approach is
overkill for most of our applications. Fortunately, PHPUnit offers some other
methods that make doing so relatively simple. The easiest method is to use an
<a href="http://www.phpunit.de/pocket_guide/3.2/en/appendixes.configuration.html">XML configuration file</a>.</p>
<p>As an example, consider the following:</p>
<pre><code class="language-xml hljs xml" data-lang="xml"><span class="hljs-tag">&lt;<span class="hljs-name">phpunit</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">testsuite</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"My Test Suite"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">directory</span>&gt;</span>./<span class="hljs-tag">&lt;/<span class="hljs-name">directory</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">testsuite</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">filter</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">whitelist</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">directory</span> <span class="hljs-attr">suffix</span>=<span class="hljs-string">".php"</span>&gt;</span>../library/<span class="hljs-tag">&lt;/<span class="hljs-name">directory</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">directory</span> <span class="hljs-attr">suffix</span>=<span class="hljs-string">".php"</span>&gt;</span>../application/<span class="hljs-tag">&lt;/<span class="hljs-name">directory</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">exclude</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">directory</span> <span class="hljs-attr">suffix</span>=<span class="hljs-string">".phtml"</span>&gt;</span>../application/<span class="hljs-tag">&lt;/<span class="hljs-name">directory</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">exclude</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">whitelist</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">filter</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">logging</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">log</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"coverage-html"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"./log/report"</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>
            <span class="hljs-attr">yui</span>=<span class="hljs-string">"true"</span> <span class="hljs-attr">highlight</span>=<span class="hljs-string">"true"</span>
            <span class="hljs-attr">lowUpperBound</span>=<span class="hljs-string">"50"</span> <span class="hljs-attr">highLowerBound</span>=<span class="hljs-string">"80"</span>/&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">log</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"testdox-html"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"./log/testdox.html"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">logging</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">phpunit</span>&gt;</span>
</code></pre>
<p>First thing to note, relative paths are relative to the configuration file.
This allows you to run your tests from anywhere in your tests tree. Second,
providing a <code>directory</code> directive to the <code>testsuite</code> directive scans for all
files ending in <code>Test.php</code> in that directory, meaning you don't have to keep a
list of your test cases manually. It's a great way to automate the suite.
Third, the filter directive allows us to determine what classes to include
and/or exclude from coverage reports. Finally, the <code>logging</code> directive lets us
specify what kinds of logs to create and where.</p>
<p>Drop the above into <code>tests/phpunit.xml</code> in your application, and you can start
writing test cases and running the suite immediately, using the following
command:</p>
<pre><code class="language-bash hljs bash" data-lang="bash">$ phpunit --configuration phpunit.xml
</code></pre>
<p>I like to group my test cases by type. I have controllers, models, and often
library code, and need to keep the tests organized both on the filesystem as
well as for running the actual tests. There are two things I do to facilitate
this.</p>
<p>First, I create directories. For instance, I have the following hierarchy in my
test suite:</p>
<pre><code class="language- hljs " data-lang="">tests/
    phpunit.xml
    TestHelper.php
    controllers/
        IndexControllerTest.php (contains IndexControllerTest)
        ErrorControllerTest.php (contains ErrorControllerTest)
        ...
    models/
        PasteTest.php           (contains PasteTest)
        DbTable/
            PasteTest.php       (contains DbTable_PasteTest)
        ...
    My/
        Form/
            Element/
                SimpleTextareaTest.php
</code></pre>
<p><code>controllers/</code> contains my controllers, <code>models/</code> contains my models. If I were
developing a modular application, I'd have something like <code>blog/controllers/</code>
instead. Library code is given the same hierarchy as is found in my <code>library/</code>
directory.</p>
<p>Second, I use docblock annotations to group my tests. I add the following to my
class-level docblock in my controller test cases:</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-comment">/**
 * <span class="hljs-doctag">@group</span> Controllers
 */</span>
</code></pre>
<p>Models get the annotation <code>@group Models</code>, etc. This allows me to run
individual sets of tests on demand:</p>
<pre><code class="language-bash hljs bash" data-lang="bash">$ phpunit --configuration phpunit.xml --group=Controllers
</code></pre>
<p>You can specify multiple <code>@group</code> annotations, which means you can separate
tests into modules, issue report identifiers, etc; additionally, you can add
the annotations to individual test methods themselves to have really
fine-grained test running capabilities.</p>
<p>Astute readers will have noticed the <code>TestHelper.php</code> file in that directory
listing earlier, and will be wondering what that's all about.</p>
<p>A test suite needs some environmental information, just like your application
does. It may need a default database adapter, altered <code>include_path</code>s,
autoloading set up, and more. Here's what my <code>TestHelper.php</code> looks like:</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-comment">/*
 * Start output buffering
 */</span>
ob_start();

<span class="hljs-comment">/*
 * Set error reporting to the level to which code must comply.
 */</span>
error_reporting( E_ALL | E_STRICT );

<span class="hljs-comment">/*
 * Set default timezone
 */</span>
date_default_timezone_set(<span class="hljs-string">'GMT'</span>);

<span class="hljs-comment">/*
 * Testing environment
 */</span>
define(<span class="hljs-string">'APPLICATION_ENV'</span>, <span class="hljs-string">'testing'</span>);

<span class="hljs-comment">/*
 * Determine the root, library, tests, and models directories
 */</span>
$root        = realpath(dirname(<span class="hljs-keyword">__FILE__</span>) . <span class="hljs-string">'/../'</span>);
$library     = $root . <span class="hljs-string">'/library'</span>;
$tests       = $root . <span class="hljs-string">'/tests'</span>;
$models      = $root . <span class="hljs-string">'/application/models'</span>;
$controllers = $root . <span class="hljs-string">'/application/controllers'</span>;

<span class="hljs-comment">/*
 * Prepend the library/, tests/, and models/ directories to the
 * include_path. This allows the tests to run out of the box.
 */</span>
$path = <span class="hljs-keyword">array</span>(
    $models,
    $library,
    $tests,
    get_include_path()
);
set_include_path(implode(PATH_SEPARATOR, $path));

<span class="hljs-comment">/**
 * Register autoloader
 */</span>
<span class="hljs-keyword">require_once</span> <span class="hljs-string">'Zend/Loader.php'</span>;
Zend_Loader::registerAutoload();

<span class="hljs-comment">/**
 * Store application root in registry
 */</span>
Zend_Registry::set(<span class="hljs-string">'testRoot'</span>, $root);
Zend_Registry::set(<span class="hljs-string">'testBootstrap'</span>, $root . <span class="hljs-string">'/application/bootstrap.php'</span>);

<span class="hljs-comment">/*
 * Unset global variables that are no longer needed.
 */</span>
<span class="hljs-keyword">unset</span>($root, $library, $models, $controllers, $tests, $path);
</code></pre>
<p>The above ensures that my <code>APPLICATION_ENV</code> constant is set appropriately, that error reporting is appropriate for tests (i.e., I want to see <em>all</em> errors), and that autoloading is enabled. Additionally, I place a couple items in my registry — the bootstrap and test root directory.</p>
<p>In each test case file, I then do a <code>require_once</code> on this file. In future
versions of PHPUnit, you'll be able to specify a bootstrap file in your
configuration XML that gets pulled in for each test case, and you'll be able to
even further automate your testing environment setup.</p>
<p>Hopefully this will get you started with your application testing; what are you
waiting for?</p>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&u=79dd2ea1d4d8855944715d09ee4c86215027fa80&s=140" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/190-Setting-up-your-Zend_Test-test-suites.html">Setting up your Zend_Test test suites</a> was originally
    published <time class="dt-published" datetime="2008-09-11T15:00:00-05:00">11 September 2008</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
  </channel>
</rss>
