<HTML>
<HEAD><!-- Template generated by Exclaimer Mail Disclaimers on 11:21:45 Thursday, 22 May 2014 -->
<STYLE type=text/css>P.ae431132-9d17-4a38-b6b5-634369783623 {
MARGIN: 0cm 0cm 0pt
}
LI.ae431132-9d17-4a38-b6b5-634369783623 {
MARGIN: 0cm 0cm 0pt
}
DIV.ae431132-9d17-4a38-b6b5-634369783623 {
MARGIN: 0cm 0cm 0pt
}
TABLE.ae431132-9d17-4a38-b6b5-634369783623Table {
MARGIN: 0cm 0cm 0pt
}
DIV.Section1 {
page: Section1
}
</STYLE>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</HEAD>
<BODY style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;">
<P class=ae431132-9d17-4a38-b6b5-634369783623>
<div id="bloop_customfont">Hey everyone,</div>
<div id="bloop_customfont"><br />
</div>
<div id="bloop_customfont">Based on our conversation in irc yesterday, I’m detailing a few proposals for the way we handle testing. Before that, I want to establish the terminology so we’re all on the same page. In a software project like this, there are generally
three types of tests: unit tests, integration tests, end-to-end tests.</div>
<div id="bloop_customfont"><br />
</div>
<div id="bloop_customfont"><b><br />
</b></div>
<div id="bloop_customfont"><b>End-to-end testing</b> is the full run-through of a service operation as an end-user would interact with it. You pass in your identity parameters, instantiate a service like Swift, and execute an operation. A real HTTP request
is sent over the wire, and a real HTTP response from the server is received. In other words, it’s a live network test of
<i>all components </i>from end to end. Right now, any time we’re communicating with the server API in our test suite, it’s an
<i>end-to-end test</i>. There doesn’t need to be many of these - just enough to test that our API works for end-users. E2E tests will typically be slow (due to network calls) - but this does not matter.</div>
<div id="bloop_customfont"><br />
</div>
<div id="bloop_customfont"><b><br />
</b></div>
<div id="bloop_customfont"><b>Integration testing </b>is like end-to-end testing except no network connections happen. All it does is test is the
<i>integration </i>between modules of the application. So if we want to test Swift operation - we’d instantiate a context object with identity parameters, then instantiate a Swift service object, and then after we’ve done the setup, finally test the operation
object. In an integration test, the flow of execution happens like it would an end-to-end test, but all we’re testing is that different components work together. This is useful for ensuring that contracts between interfaces are being satisfied, etc. I don’t
think we need to worry about writing these.</div>
<div id="bloop_customfont"><br />
</div>
<div id="bloop_customfont"><br />
</div>
<div id="bloop_customfont"><b>Unit testing</b> is very different from both of the above. Instead, you test extremely small “units” of behavior in a particular class. Each test needs to be fully isolated and have only 1 responsibility (i.e. test one unit). The
class you’re testing should not collaborate with real objects; instead, you need to pass in mocks. So, if we’re unit testing a Swift operation, instead of using a real service or transport client - we mock them and use the mock objects in our tests. If our
tested class invokes methods on this mock, we also need to explicitly define how it does so. For example, if we’re testing a method that calls `$this->client->foo()` internally and expects a response, we need to explicitly tell the mocked client object to
return a value when its “foo” method is called. We can also be more granular and strict: we can say that the method should only be called with certain arguments, that the method should be called x number of times. With unit tests, you are defining and testing
communication promises. The point of doing this is that you’re testing HOW your object communicates in a precise way. Because they’re isolated, there should be hundreds of unit tests, and they should be very quick.</div>
<div id="bloop_customfont"><br />
</div>
<div id="bloop_customfont"><br />
</div>
<div id="bloop_customfont">Here’s an example of how you’d mock for unit tests in phpunit: <a href="https://gist.github.com/jamiehannaford/ad7f389466ac5dcafe7a">https://gist.github.com/jamiehannaford/ad7f389466ac5dcafe7a</a></div>
<div id="bloop_customfont"><br />
</div>
<div id="bloop_customfont">There was a proposal made that we should just inject a HTTP client that doesn’t make real transactions - but that is not feasible because it goes against what a unit test is. If you were to do this, your tested class would be executing
UNMOCKED methods against a REAL object - making as many calls as it wants. It would not be isolated, and for that reason it would not be a unit test. It would be an
<i>integration test</i> because you’re forcing your tested class to interact like it would in the wild. Instead, you should mock every collaborator and explicitly define which calls are made against them by your tested class.</div>
<div id="bloop_customfont"><br />
</div>
<div id="bloop_customfont">There are amazing libraries out there like Prophecy and phpspec which mocking a whole load easier and more natural - but I assume nobody wants to move away from phpunit…</div>
<div id="bloop_customfont"><br />
</div>
<div id="bloop_customfont"><b><br />
</b></div>
<div id="bloop_customfont"><b>Proposal going forward</b></div>
<div id="bloop_customfont"><br />
</div>
<div id="bloop_customfont">So, here are my proposals for our current library:</div>
<div id="bloop_customfont"><br />
</div>
<div id="bloop_customfont">1. Refactor our unit tests to use mocking instead of real HTTP/network calls. If a class relies on dependencies or collaborators, they will need to be mocked.</div>
<div id="bloop_customfont"><br />
</div>
<div id="bloop_customfont">2. As services are added (Swift, Nova, Keystone), end-to-end tests are added for each. We’d therefore ensure that our SDK is interacting with the real API as expected.</div>
<div id="bloop_customfont"><br />
</div>
<div id="bloop_customfont">3. Never use the @depends annotation on unit tests, because it makes them tightly coupled with each other and brittle. A unit test is supposed to be completely autonomous and independent - it should never depend on the output of another
test. </div>
<div id="bloop_customfont"><br />
</div>
<div id="bloop_customfont">4. Use the “setUp” and “tearDown” helper methods to easily set up test fixtures</div>
<div id="bloop_customfont"><br />
</div>
<div id="bloop_customfont">5. In our source code, we need to make use of Dependency Injection AS MUCH AS POSSIBLE because it’s easier to test. If we don’t (choosing to directly instantiate objects in our code), it introduces tight coupling and is extremely
hard to mock.</div>
<div id="bloop_customfont"><br />
</div>
<div id="bloop_customfont"><br />
</div>
<div id="bloop_customfont"><br />
</div>
<div id="bloop_customfont">Does anybody have any major disagreements with my above proposal?</div>
<div id="bloop_customfont"><br />
</div>
<div id="bloop_customfont"><br />
</div>
<div id="bloop_customfont">Jamie</div>
</P>
<P class=ae431132-9d17-4a38-b6b5-634369783623> </P>
<P class=ae431132-9d17-4a38-b6b5-634369783623>
<TABLE border=0 cellPadding=0 width=504>
<TBODY>
<TR>
<TD style="WIDTH: 270px" class=LEFT_ALIGNED><span style='font-family:Verdana; font-size:small; '>Jamie Hannaford</span><BR /><span style='font-family:Verdana; font-size:x-small; '>Software Developer III - CH</span></TD>
<TD style="WIDTH: 281px"><IMG alt="experience Fanatical Support" align=right src="cid:imagebd91e8.JPG@48b720d1.4fb7695b" width=159 height=17 /></TD></TR>
<TR class=LEFT_ALIGNED>
<TD colSpan=2><IMG alt=LINE src="cid:imageb655a1.JPG@39ce4248.4eb6d4d3" width=504 height=4 /></TD></TR>
<TR>
<TD class=CONTACTINFO><span style='font-family:Calibri; '><table class=ae431132-9d17-4a38-b6b5-634369783623Table><tr><td><span style='font-family:Verdana; font-size:x-small; '>Tel: </span></td><td><span style='font-family:Verdana; font-size:x-small; '>+41434303908</span></td></tr><tr><td><span style='font-family:Verdana; font-size:x-small; '>Mob: </span></td><td><span style='font-family:Verdana; font-size:x-small; '>+41791009767</span></td></tr></table></span></TD>
<TD class=RIGHT_ALIGNED><IMG alt=Rackspace src="cid:imagedf3249.JPG@015341f7.4d920784" width=280 height=60 /></TD></TR>
<TR class=LEFT_ALIGNED>
<TD class=CONTACTINFO colSpan=2><IMG src="cid:image0d9919.JPG@f1598d05.4bafc1a5" width=504 height=3 /></TD></TR></TBODY></TABLE></P>
<P class=ae431132-9d17-4a38-b6b5-634369783623> </P>
<P class=ae431132-9d17-4a38-b6b5-634369783623></P><span style="font-size: 11px;">Rackspace International GmbH a company registered in the Canton of Zurich, Switzerland (company identification number CH-020.4.047.077-1) whose registered office is at Pfingstweidstrasse 60, 8005 Zurich, Switzerland. Rackspace International GmbH privacy policy can be viewed at www.rackspace.co.uk/legal/swiss-privacy-policy<br>-<br>Rackspace Hosting Australia PTY LTD a company registered in the state of Victoria, Australia (company registered number ACN 153 275 524) whose registered office is at Suite 3, Level 7, 210 George Street, Sydney, NSW 2000, Australia. Rackspace Hosting Australia PTY LTD privacy policy can be viewed at www.rackspace.com.au/company/legal-privacy-statement.php<br>-<span style="font-size: 11px;"></span><br>Rackspace US, Inc, 5000 Walzem Road, San Antonio, Texas 78218, United States of America</span><br><span style="font-size: 11px;">Rackspace US, Inc privacy policy can be viewed at www.rackspace.com/information/legal/privacystatement</span><br><span style="font-size: 11px;">-</span><br><span style="font-size: 11px;">Rackspace Limited is a company registered in England & Wales (company registered number 03897010) whose registered office is at 5 Millington Road, Hyde Park Hayes, Middlesex UB3 4AZ.</span><br><span style="font-size: 11px;">Rackspace Limited privacy policy can be viewed at www.rackspace.co.uk/legal/privacy-policy</span><br><span style="font-size: 11px;">-</span><br><span style="font-size: 11px;">Rackspace Benelux B.V. is a company registered in the Netherlands (company KvK nummer 34276327) whose registered office is at Teleportboulevard 110, 1043 EJ Amsterdam.</span><br><span style="font-size: 11px;">Rackspace Benelux B.V privacy policy can be viewed at www.rackspace.nl/juridisch/privacy-policy</span><br><span style="font-size: 11px;">-</span><br><span style="font-size: 11px;">Rackspace Asia Limited is a company registered in Hong Kong (Company no: 1211294) whose registered office is at 9/F, Cambridge House, Taikoo Place, 979 King's Road, Quarry Bay, Hong Kong.</span><br><span style="font-size: 11px;">Rackspace Asia Limited privacy policy can be viewed at www.rackspace.com.hk/company/legal-privacy-statement.php</span><br><span style="font-size: 11px;">-</span><br><span style="font-size: 11px;">This e-mail message (including any attachments or embedded documents) is intended for the exclusive and confidential use of the individual or entity to which this message is addressed, and unless otherwise expressly indicated, is confidential and privileged information of Rackspace. Any dissemination, distribution or copying of the enclosed material is prohibited. If you receive this transmission in error, please notify us immediately by e-mail at abuse@rackspace.com and delete the original message. Your cooperation is appreciated.</span></BODY>
</HTML>