<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>tdd &#8211; Software, Fitness, and Gaming &#8211; Jesse Warden</title>
	<atom:link href="https://jessewarden.com/tag/tdd/feed" rel="self" type="application/rss+xml" />
	<link>https://jessewarden.com</link>
	<description>Software &#124; Fitness &#124; Gaming</description>
	<lastBuildDate>Fri, 29 Apr 2016 22:35:32 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://jessewarden.com/wp-content/uploads/2016/08/cropped-Lambda2-32x32.png</url>
	<title>tdd &#8211; Software, Fitness, and Gaming &#8211; Jesse Warden</title>
	<link>https://jessewarden.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Experiences in Managing Software Development Through Kanban &#038; Trello</title>
		<link>https://jessewarden.com/2016/04/experiences-in-managing-software-development-through-kanban-trello.html</link>
		
		<dc:creator><![CDATA[JesterXL]]></dc:creator>
		<pubDate>Sat, 16 Apr 2016 20:02:57 +0000</pubDate>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[agile]]></category>
		<category><![CDATA[angular]]></category>
		<category><![CDATA[bdd]]></category>
		<category><![CDATA[behaviordrivendevelopment]]></category>
		<category><![CDATA[cucumber]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[gherkin]]></category>
		<category><![CDATA[kanban]]></category>
		<category><![CDATA[leadership]]></category>
		<category><![CDATA[management]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[protractor]]></category>
		<category><![CDATA[scrum]]></category>
		<category><![CDATA[tdd]]></category>
		<category><![CDATA[testdrivendevelopment]]></category>
		<category><![CDATA[trello]]></category>
		<category><![CDATA[unitests]]></category>
		<guid isPermaLink="false">http://jessewarden.com/?p=5112</guid>

					<description><![CDATA[Introduction On my last project, I managed a team developing an application to manage hospitality locations. Given our requirements were constantly in flux, the contracts were on a short cycle, and the team was generally new to enterprise software development, I chose a Kanban style approach to managing and delivering it. I wanted to share [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>Introduction</h1>
<p>On my last project, I managed a team developing an application to manage hospitality locations. Given our requirements were constantly in flux, the contracts were on a short cycle, and the team was generally new to enterprise software development, I chose a Kanban style approach to managing and delivering it. I wanted to share with you the rationale, methodology, challenges, and the surprising change to my role while on the project.<br />
<span id="more-5112"></span></p>
<h1>Why Kanban vs Scrum?</h1>
<p>Scrum has too many meetings, requires a well groomed backlog, and assumes senior developers so that they canÂ accurately task &amp; plan their stories.</p>
<h2>Junior to Mid-Level Team</h2>
<p>Given I was running my mid-level team in an Enterprise setting, I knew others would be more than happy to sabotage our teams productivity with meetings of their own. Part of the solution, not part of the problem. New team members, both onshore and offshore, who I expected to be reasonably cross functional whether they liked it or not, needed all the time they could to focus and learn quickly.</p>
<h2>No Solid Requirements</h2>
<p>Given staffing wasÂ changing bi-weekly with an my on-going effort to teach the Subject Matter Experts (SME&#8217;s) turned Business Analysts (BA&#8217;s) how to create properly groomed stories, there wasn&#8217;t anything the team could commit to within a reasonable timeframe. For example, it took us 8Â <a href="http://programmers.stackexchange.com/questions/176063/how-to-be-successful-at-bdd-specifications-workshops">workshops</a>Â over 3 weeks to get to a solid understanding of what we thought we were building.</p>
<h2>No CICD</h2>
<p>We also had no buildÂ nor <a href="https://en.wikipedia.org/wiki/DevOps">DevOps</a>Â in place to facilitate <a href="https://www.thoughtworks.com/continuous-integration">ContinuousÂ Integration</a> and <a href="https://www.thoughtworks.com/continuous-delivery">Continuous Delivery</a>.Â Thus we had no ability for weeks to deliver a working, high quality feature because there was no build to allow Developers &amp; Quality Assurance toÂ verify quality, nor server to deploy it to.</p>
<h2>No Roles, Just Fullstack / Cross Functional</h2>
<p>Having a <a href="https://www.mountaingoatsoftware.com/agile/scrum/product-owner">Product Owner</a> assumes you have someone either in Business, or who represents them, that knows what to build. The client asked us to use our expertise to help them out in true Consulting style.Â Thus there was no Product Owner.</p>
<p>There was no need for a <a href="http://whatis.techtarget.com/definition/scrum-master">Scrum Master</a>. <a href="https://www.mountaingoatsoftware.com/agile/scrum/sprint-planning-meeting">Sprint Planning</a>Â was pointless because we couldn&#8217;t plan 1 to 2 weeks in advanced since high level Epic&#8217;s were still beingÂ both defined, priced, and architecturally validated. ForÂ months. I already knew what the team was working on, and so did they, by their small Trello cards. If people had blockers, they asked me or the team over <a href="https://slack.com/">Slack</a> andÂ we collectively resolved it. There was no need for <a href="https://www.mountaingoatsoftware.com/agile/scrum/sprint-retrospective">Retrospectives</a> because there were no Sprints since things changed daily so you couldn&#8217;t effectively reflect on what happened the past week because it was ever changing.Â There were no roles beyond everyone coding the client, server, and some of the DevOps together.</p>
<p>Scrum would of beenÂ lot of ceremony with noÂ value.</p>
<h1>EnterÂ Kanban</h1>
<p>What <a href="https://www.atlassian.com/agile/kanban">Kanban</a> does well is allow you to change quickly, allow the team to be productive despite the chaos, with a continuous flow of delivering working software that&#8217;s in sharp contrast to the insanity outside their productive world. Unlike <a href="https://www.scrumalliance.org/community/articles/2014/july/scrum-vs-kanban">Scrum</a>, you much more quickly visualize the work going on &#8220;today&#8221; and identify problems sooner than later. Since the work in progress tends to be smaller, you can flush out bottlenecks in the process sooner. You can create <a href="http://leankit.com/learn/kanban/kanban-board-examples-for-development-and-operations/">swimlanes</a> and also identify which ones have bottlenecks.</p>
<h2>Flexible to Ever Changing Direction</h2>
<p>As each new day brought in new or modified requirements, role changes, and improved DevOps and API offerings, I wouldÂ changeÂ the Backlog to match &#8220;today&#8221;. Given we had no build, nor DevOps starting from scratch, I had a lot of flexibility to inject more build specific tasks so as to keep away from <a href="http://martinfowler.com/bliki/Yagni.html">Yagni</a>Â until we got a solid enough user story. &#8220;No user stories, nor API? No problem, get <a href="https://mochajs.org/">Mocha</a> working with our <a href="https://nodejs.org/en/">Node</a> code.&#8221; I&#8217;d attempt to stay 1 to 4 days ahead of my team. This was to ensure they were working on what I knew at the time to be real and providing client &amp; user value.</p>
<h2>Productive Despite Chaos</h2>
<p>Politically, it helped ensure we were being productive and thus visually showing we&#8217;re using the client&#8217;s money effectively with the fast ability to change course if they wanted something changed faster than aÂ Scrum Sprint would typically allow. This happened often.</p>
<h2>Learning the Team&#8217;s Strengths, Weaknesses, and Desires</h2>
<p>I had a new, junior to mid-level Development team and QA team, on a greenfieldÂ client (meaning no existing infrastructure or code), with ever changingÂ requirements, staffing, and contract lengths. Since the team was new and learning the entire <a href="https://en.wikipedia.org/wiki/Systems_development_life_cycle">Software Development Lifecycle</a> whilst me doing my best to shield them from politics, lack of a CICD process,Â lack of requirements, and nothing pre-built for them via <a href="http://yeoman.io/">Yeoman</a> generators / starter projects&#8230; I knew things would be slow and unpredictable at first.</p>
<p>What I didn&#8217;t know was the team. I didn&#8217;tÂ know their strengths, weaknesses, and most importantly, desires. Happy developers are productive developers. A lot of people say they are <a href="http://andyshora.com/full-stack-developers.html">fullstack</a> to ensure they are employable or because they are insecure that their speciality skill set cannot stand on it&#8217;s own. That or they like working in smaller, more cross functional groups.</p>
<p>As much as I expected the team to touch all parts of the development stack, including myself, you always have people who naturally gravitate somewhere, or like to be pushed to a particular area like API&#8217;s, services, components, or build level tasks. This should be encouraged just as much as being cross functional to get the most out of them, and the team. Additionally, as the project matures, you have less of a need to be cross functional as often, and tend to see people dive deep over time.</p>
<h1>Creating Tasks in Trello</h1>
<p>I also didn&#8217;t know the team&#8217;s ability to estimate their own tasks. It didn&#8217;t matter since the user stories weren&#8217;t defined enough for them to do so. Thus, I broke all tasks down for the team and included additional DevOpsÂ and QAÂ tasks as well into small units. We used <a href="https://trello.com/">Trello</a>, a real-time collaborative project board full of cards, to keep track of the work.</p>
<p>We had 6 columns in our Trello board, from left to right:</p>
<ol>
<li><strong>Bulletin Board</strong>: All the documents &amp; images for our project</li>
<li><strong>Undefined</strong>: Stories &amp; Tasks I didn&#8217;t have enough clarity on for the team to work on.</li>
<li><strong>Defined</strong>: Tasks I fleshed out enough toÂ ensure anyone on the team could work on with clearly defined success criteria, easily merged into a <a href="https://github.com/">Github</a> <a href="https://help.github.com/articles/using-pull-requests/">Pull Request</a>, and colored with the swimlane it belonged to: Testing, Client UI, Node API, DevOps, and <a href="https://en.wikipedia.org/wiki/User_experience_design">UX</a>.</li>
<li><strong>Working On It</strong>: What tasks were being actively worked on in the team. I ensured only 1 card per developer</li>
<li><strong>Done</strong>: For tasks that were done and developer tested, but not QA approved via them manually testing the Card&#8217;s associated PR.</li>
<li><strong>Approved</strong>: QA approved PR&#8217;s that merged into the dev branch and deployed via <a href="https://jenkins.io/">Jenkins</a> <a href="https://www.docker.com/">Docker</a> build.</li>
</ol>
<p><img fetchpriority="high" decoding="async" class="alignnone size-full wp-image-5113" src="http://jessewarden.com/wp-content/uploads/2016/04/trello-board.png" alt="trello-board" width="720" height="456" srcset="https://jessewarden.com/wp-content/uploads/2016/04/trello-board.png 720w, https://jessewarden.com/wp-content/uploads/2016/04/trello-board-300x190.png 300w" sizes="(max-width: 720px) 100vw, 720px" /></p>
<h2>Observe the Flow of Development&#8230;</h2>
<p>What happened next sold me on one of the key strengths of Kanban.</p>
<p>Every day I could immediately see problems. Instantly. It happened just like <a href="https://www.linkedin.com/in/andrea-ross-csm-sa-0a056b3b">Andrea Ross</a> <a href="http://jessewarden.com/2013/08/kanban-paper-airplane-factory.html">said it would</a>, and I&#8217;d see where bottlenecks were in the process. Each column in Trello would suddenly get overflowed with cards. You could be near blind, simply squint at the board so you couldn&#8217;t actually read anything and STILL SEE IT. The size of the columns told all: you have a bottleneck somewhere here.</p>
<p>It&#8217;s called <a href="https://stefanroock.wordpress.com/2010/03/02/kanban-definition-of-lead-time-and-cycle-time/">Cycle Time</a>: how long a piece of work goes from left to right. You want toÂ ensure once cards are created, they speed from Undefined to Accepted (left to right, start to finish) as quickly as possible. Typically that process isn&#8217;t linear; SOMEWHERE in the journey there is always a bottleneck.</p>
<h2>&#8230; Adjust as Necessary</h2>
<h3>How do I know I&#8217;m done?</h3>
<p>The first one was the success criteria I gave wasn&#8217;t clear enough. 90% ofÂ my created cards in Defined were moved back to Undefined by the team. Once I gave better success criteria, the development team started to chew through them. I wouldn&#8217;t hear from them for hours, then cards would suddenly start piling up in the Done column w/PR&#8217;s to boot.</p>
<h3>What does the UI look like?</h3>
<p>The second one was lack of good <a href="https://en.wikipedia.org/wiki/Website_wireframe">wireframes</a> and <a href="http://graphicdesign.stackexchange.com/questions/30860/what-is-the-difference-between-wireframes-and-mockups">designs</a> to illustrate both the layout and interactions of how the UI worked. We didn&#8217;t yet have budget for a UX resource, so I spent the time myselfÂ building low fidelity wireframes that were as accurate as possible and then creating design comps matching our <a href="https://www.google.com/design/spec/material-design/introduction.html">Material Design</a>Â style guide. I ensured all new cards had relevant design artifacts attached. If the wireframe/design comp changed, I&#8217;d move the card from Defined back to Undefined to ensure the team didn&#8217;t touch it. If it was too late, I&#8217;d create an iteration card to modify an existing piece of work with the updated UI/functionality change.</p>
<h3>How do I test itÂ works?</h3>
<p>The third one was the inability for QA to test functionality as cards started piling up in the Done column. QA didn&#8217;t yet have the build running locally, nor a QA environment to test on, nor a set of tools to help them automate it, nor a lead to help mentor them towards this.</p>
<p>So I picked up the torch, implemented <a href="http://www.protractortest.org">Angular&#8217;s Protractor</a> with theÂ <a href="https://github.com/mattfritz/protractor-cucumber-framework">Cucumber</a> version, then had a team member get an actual working feature through <a href="http://gulpjs.com/">Gulp</a>. I then worked with the QA team and BA&#8217;s to help define better Cucumber features through workshops so they were easier to test. I attached these as additional artifacts to each card where applicable.</p>
<p>Finally, we started Dockerizing our build to use throughÂ <a href="https://kitematic.com/">Kitematic</a> &amp; <a href="https://hub.docker.com/">DockerHub</a>.Â Given how hard it was to get <a href="http://redis.io/">Redis</a> + Node working the same between the Developer&#8217;s Macs and the QA&#8217;sÂ Windows machines with various lack of admin rights, this helped ensure things actually worked, quickly, without debugging install or configuration issues.</p>
<h3>Continually Improve</h3>
<p>This process never stopped. Sometimes it was smallÂ bottlenecks or even just blockers and we&#8217;d do our best to improve the process.Â Despite the politics, climate of unknowing, and constant readjustment of requirements &amp; processes&#8230; it felt good to be making both progress and improving the process.</p>
<p>Developers got to zone out by donningÂ headphonesÂ toÂ jam on code all day. Working codeÂ continually emerged as long as I fed this process.</p>
<p>We almost got to the point where the developers had no clue about the ever changing conditions on the ground with the client, ignored it when I brought it up, and focused strictly on questions about specific tasks. I&#8217;d call that a process win.</p>
<h1>Challenges</h1>
<p>It wasn&#8217;t all rose colored glasses.</p>
<h2>The Importance of Good, Upfront DevOps</h2>
<p>The main pain point throughout the entire process was our DevOps starting late in the cycle. Without a good CICD process, Scrum and Kanban don&#8217;t really seem to work all that well in tracking &#8220;actual work&#8221; because no actual work&#8230; works. Now, the CIÂ portion we knocked out of the park ourselves and quickly while waiting for confirmed requirements using Github and Jenkins in Docker + <a href="https://aws.amazon.com/">AWS</a>. Mostly. The CD, however, took awhile.</p>
<p>What we wanted at first was once a PR was approved, the code would, after a successful Jenkins build, deploy a Docker container of our code to a publicly accessible Amazon Web Service (AWS) instance. It took us about 3 months to get that going given our resource constraints &amp; timing. In the interim, we did a lot of <a href="https://en.wikipedia.org/wiki/Mock_object">mocks</a> and testing on localhost with <a href="https://ngrok.com/">ngrok</a> for demos.</p>
<p>Once our Docker deployment was working we started having code be deployed without our knowledge in a good way; the development teamÂ just focused on completing cards, and eventually the QA would focus on verifying manually what made it through the automated QA process to the server matched up.</p>
<p>The latter took forever simply because I was stretched too thin running the Development team, helping the DevOps team, doing my own wireframes and design comps, mentoring the BA&#8217;s to writeÂ awesome user stories via <a href="https://dannorth.net/introducing-bdd/">Behavioral Driven Development</a> to minimize our story grooming sessions, and keeping Senior Management in the loop.</p>
<p>Even with Analysts starting the DevOps, it&#8217;s clear having them full time on that endeavor payed off big time. In the future, I&#8217;m curious if I&#8217;d rather focus on that full time myself since it seems to have the largest, cross team impact regardless of whether the requirements, UX, and CIÂ are in a good or bad spot.</p>
<h2>Wireframing &amp; Designing at the Same Time vs. Staggered</h2>
<p>While me being the same person to do the wireframes made it easier to build design comps around them, it simnifically reduced the time I could spend with other teams.Â When the Undefined column would get too full, I&#8217;d have to spend the early part of the week ensuring I had enough information to wireframe. I&#8217;d then spend the weekend onÂ the design comps and then break them down into easily tackled, small PR tasks in Trello. This wasn&#8217;t sustainable and I knew it, but was banking on getting budget for UX resources.</p>
<p>While I was helping the BA&#8217;s, Development Team, and QA by ensuring the stories had a visual component toÂ help ensure we&#8217;re all on the same page of what theÂ user story looked like, I&#8217;d end up neglecting other things like refining those very stories, not unblocking the development team when they&#8217;d get stuck on build or architecture issues, nor helping push the DevOps team to help the QA do their job.</p>
<p>Rather than complain, I made a daily tactical call on what to focus on based on what Trello was telling me. Once we got the UX resourceÂ onboard, he worked aside the BA&#8217;s and that helped a ton; at that point I could just match the design comps to his wireframes, cutting my work in half + his were of insanely higher quality for talent &amp; focus reasons.</p>
<p>What this tells me is that unless I have a huge backlog of build and DevOps work in the pipeline, I&#8217;ll be hard pressed in the future to keep my development team busy with those tasks for a long timeÂ without quickly needing a proper UX team member(s).</p>
<h2>QA in Lean Engineering</h2>
<p>I didn&#8217;t have enough seniors to delegate management tasks to, and coupled with my CD problems, IÂ struggled to keep QA productive. While our developers were using <a href="http://eslint.org/">linting</a> <a href="https://www.typescriptlang.org/">compilers</a>, <a href="https://github.com/vigetlabs/grunt-complexity">complexity metrics</a>, unit and integration testing with <a href="https://www.youtube.com/watch?v=o6KSOs-N75o">end to end testing</a>, no one was laser focused on improving the latter part of the QA CD pipeline. I&#8217;d made some headway in getting QA involved in the beginning to help contribute to ensuring good user stories came out of our workshops. Where I struggledÂ was giving them enough of my time to teach them basic JavaScript coding, DevOps, and helping them walk through their testing plans on what we did have to start to develop a cadence.</p>
<p>A lot of this was we just didn&#8217;t have that much to test yet and the other was&#8230; well, nothing. I did the best I could working insane hours. If I were to do it again, I&#8217;d assign a senior dev interested in furthering their testing &amp; DevOps chops to work with them on owning the CD process, and ensuring a good quality pipeline.</p>
<p>In Lean Engineering, QA is no longer thrown code to test weeks or months later. Instead, they are brought into the beginning of the process and the end to improve the entire pipeline. You can&#8217;t do that if you don&#8217;t have a DevOps pipeline.</p>
<h2>User Feedback</h2>
<p>The same problem I had with QA I had with user feedback. Part ofÂ Lean engineering with Kanban is continuously improve not just the process, but the software. You do this by giving the working build to a user, testing it, and taking their feedback BACK into the process. While doing wireframes, I did informal and adhoc user interviews, created basic <a href="https://www.smashingmagazine.com/2014/08/a-closer-look-at-personas-part-1/">Persona&#8217;s</a> to differentiate who we were targeting, but did not get to validate this with released software until late in the cycle.</p>
<p>This actually wasn&#8217;t much of a bad thing, but rather, a challenge because a working build didn&#8217;t emerge until much later in the cycle, so we just did localhost demo&#8217;s &amp; testing vs. &#8220;use whatever device you have on your person or will use in your job&#8221;. I had already had extensive, informal discussions with the target users and really liked them as people. It just came up when I&#8217;d look at swimlanes via colors in Trello cards, the features had a huge cycle time in knowing if they were valid or not from user testing.</p>
<h1>Role Changes</h1>
<p>Traditionally in Agile, I&#8217;ve found I do most of my management efforts on Sprint Planning and post Retrospective. I ensure the requirements are rock solid and follow up on loose ends, and take action items seriously during retrospectives where new things need to be implemented or changed. The rest of the time I architect, pair program, and code.</p>
<p>In Kanban, it was very different. My role, daily, was to manage away problems for the team. Instead of a weekly or bi-weekly discovery, this was daily to hourly. I&#8217;d adjust based on what Trello was telling me. It gave me a greater insight into how my management efforts positively and negatively affected the team.</p>
<p>I also liked continually working with the team to improve our process. I&#8217;ve done that before in teams with Scrum, but process improvement usually fell behind &#8220;getting my story done&#8221; in terms of priority. In Kanban, fixing the bottleneck and improvingÂ the process is the priority.</p>
<p>I&#8217;ve found I really like Kanban. The consulting world is full of extremely hard software problems surrounded by politics and chaos. I love thoseÂ aspectsÂ and Kanban is now my tool of choice for managing teams within it.</p>
<h1>Citations</h1>
<p>I wanted to thank <a href="http://joelhooks.com/">Joel Hooks</a> forÂ telling me about Kanban being an alternative to ScrumÂ years ago. If Joel likes something, I typically trust his judgement that it must be good.</p>
<p>Also thanks to my manager, <a href="https://www.linkedin.com/in/mlancast">Matt Lancaster</a>, for teaching me about Lean engineering processes. You can see him speak about the processÂ below.</p>
<p><iframe src="https://www.youtube.com/embed/q2eyhFVWuKY" width="640" height="360" frameborder="0" allowfullscreen="allowfullscreen"></iframe></p>
<p>Thanks to <a href="https://www.linkedin.com/in/eric-motazedi-648a0490">Eric Motazedi</a>Â for teaching me about BDD and why <a href="http://programmers.stackexchange.com/questions/176063/how-to-be-successful-at-bdd-specifications-workshops">workshops</a> are so important.</p>
<p>FinallyÂ thanks to the Richmond <a href="http://www.meetup.com/Capital-Kanban/">Capital Kanban</a> group for teaching me more about how <a href="http://jessewarden.com/2013/08/kanban-paper-airplane-factory.html">Kanban works</a>.</p>
<p>&nbsp;</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Unit Testing in Corona SDK Using Lunatest</title>
		<link>https://jessewarden.com/2012/07/unit-testing-in-corona-sdk-using-lunatest.html</link>
					<comments>https://jessewarden.com/2012/07/unit-testing-in-corona-sdk-using-lunatest.html#comments</comments>
		
		<dc:creator><![CDATA[JesterXL]]></dc:creator>
		<pubDate>Sat, 07 Jul 2012 13:10:47 +0000</pubDate>
				<category><![CDATA[CoronaSDK]]></category>
		<category><![CDATA[corona]]></category>
		<category><![CDATA[coronasdk]]></category>
		<category><![CDATA[lua]]></category>
		<category><![CDATA[tdd]]></category>
		<category><![CDATA[unittest]]></category>
		<guid isPermaLink="false">http://jessewarden.com/?p=3188</guid>

					<description><![CDATA[In this article I &#8216;ll give you an overview of why you&#8217;d want to unit test your Lua code in Corona SDK, what features Lunatest has, a walk you through some real-world unit tests and suites I&#8217;ve written. I&#8217;ve forked Lunatest on Github to make it work with Corona SDK. This blog post has a [&#8230;]]]></description>
										<content:encoded><![CDATA[<p><a href="http://jessewarden.com/2012/07/unit-testing-in-corona-sdk-using-lunatest.html"><img decoding="async" style="padding-right: 8px;" src="http://jessewarden.com/archives/blogentryimages/lunatest/lunatest.jpg" alt="" width="320" height="213" align="left" /></a>In this article I &#8216;ll give you an overview of why you&#8217;d want to unit test your Lua code in Corona SDK, what features <a href="https://github.com/silentbicycle/lunatest">Lunatest</a> has, a walk you through some real-world unit tests and suites I&#8217;ve written. <a href="https://github.com/JesterXL/lunatest">I&#8217;ve forked Lunatest</a> on Github to make it work with Corona SDK. This blog post has a companion video embedded below.</p>
<p>&nbsp;</p>
<p><iframe loading="lazy" width="640" height="360" src="http://www.youtube.com/embed/szEbqu6_YRc" frameborder="0" allowfullscreen></iframe></p>
<p><span id="more-3188"></span><strong>Introduction: Why Unit Test?</strong></p>
<p>Lua in Corona SDK has 3 issues when your game/application code base grows to any large size.</p>
<p>First, Lua is a dynamic language much like JavaScript, Ruby, and Python. As such, you have little to no help from the compiler to ensure your code expects even basic parameters being passed to your functions as well as misspellings.</p>
<p>Secondly, Lua is dynamic at runtime. You actually need to run the code to see how it actually works. Examples include combining strings together to dynamically access properties on dynamically created objects in anÂ asynchronousÂ way.</p>
<p>Third, even if encapsulated, you have no way of knowing if your new code breaks existing code, or if modifying existing code allows it to work the same way with some assurance. This problem is not unique to Lua, it&#8217;s unique to any complex code base regardless of language.</p>
<p>All 3 combined necessitate a need for <a href="http://en.wikipedia.org/wiki/Unit_testing">unit tests</a>. Some would argue even just 1 of the above.</p>
<p><strong>Anatomy of Unit Testing</strong></p>
<p>Unit testing, as far as we&#8217;re concerned with Lua, are a bunch of functions that make sure things work as expected. Inside of those functions, you write those expectations about how you expect things to work as a bunch of assert functions.Â These groups of functions aren&#8217;t actually part of your main code base; they&#8217;re grouped together in a test folder and called a test suite. The more of them you have, the more test coverage you have.</p>
<p>TDD or <a href="http://en.wikipedia.org/wiki/Test-driven_development">Test Driven Development</a> is where you actually write the above paragraph test code first, and THEN actually write the code it&#8217;s testing afterwards. You start with writing a test that fails, you write the code to make it pass, and then ensure the test passes. Then you repeat.</p>
<p>The above 2 paragraphs can, and do fill books with the details of TDD &#038; unit testing&#8230; but that&#8217;s all you need to know for now. Heck, you can ignore everything I write here, start to proactively use assert, and your coding life will improve a lot.</p>
<p><strong>Asserts</strong><br />
Let&#8217;s start at the beginning. Lua already has an expectation function, called &#8220;assert&#8221;. It looks like this:</p>
<pre lang="lua">local wubWubWub = true
assert(wubWubWub, "Someone forgot to drop the bass.")</pre>
<p>This code asserts or &#8220;states positively&#8221; that the variable is true. If it were false, an error would be thrown with that string &#8220;Someone forgot to drop the bass.&#8221; passed into the error function. If you&#8217;re not aware, the error function in Lua stops execution of the current script and prints whatever string it has to the console/terminal. Secondly, all functions in Lua are implied to be successful if they return true.</p>
<p>Even without unit testing, using assert, you can be proactive in finding errors. For example, I use it all the time in manual getter/setters in Lua (not metatable ones, the set/get + method name convention). Since Lua has no typing system, I ensure my inputs are sanitized like so:</p>
<pre lang="lua">function setSpeed(newValue)
   assert(newValue ~= nil, "You cannot set speed to nil.")
   assert(type(newValue) == "number", "You must set speed to a number value.")
   self.speed = newValue
end</pre>
<p>Those 2 functions alone find ALL kinds of silly bugs where someone, somewhere accidentally set a value to nil and it made it&#8217;s way deep into the bowels of some class, and I&#8217;m wondering who&#8217;s fault it is. When everyone starts doing this, it makes it really easy to find who caused the bug, and quickly.</p>
<p>Yes, there is a performance cost to assert. However, it&#8217;s easier to remove a bunch of assert functions scattered everywhere via a Find / Replace from solid code then it is at add them to code that runs very fast with lots of unknown bugs.</p>
<p><strong>Moar Asserts</strong></p>
<p>Just about every testing framework expands upon the above function. In fact, 80% of what they offer in their libraries and frameworks are additional assert functions. Why? Three reasons. First, would you rather write this?</p>
<pre lang="lua">local icon = display.newImage("icon.png")
assert(icon ~= nil, "Icon image cannot be found.")</pre>
<p>or this:</p>
<pre lang="lua">local icon = display.newImage("icon.png")
assert_not_nil(icon, "Icon image cannot be found.")</pre>
<p>The second reason is it&#8217;s more clear what that is testing; the function name alone tells you what you need to know before you&#8217;ve even made it to the parameters.</p>
<p>Here&#8217;s another example:</p>
<pre lang="lua">local currentSpeed = character.speed
character:setSpeed(currentSpeed + 1)
assert(character.speed > currentSpeed, "Character speed did not increase.")</pre>
<p>vs writing:</p>
<pre lang="lua">local currentSpeed = character.speed
character:setSpeed(currentSpeed + 1)
assert_gt(character.speed, currentSpeed, "Character speed did not increase.")</pre>
<p>Now this one may appear backwards; &#8220;A comma vs. using the normal mathematical construct!?&#8221;</p>
<p>Keep in mind, however, many bugs are caused by misplaced operators. For example, developers often will use = instead of == to assign a value, or they&#8217;ll use > vs. >= for edge cases, etc. In writing that code, it&#8217;s completely legal, and Lua&#8217;s interpreter won&#8217;t give you an error when you run it. Using assert_gt in this instance will ensure your expected value is there, as well as ensure you&#8217;ve use the operator correctly. If not, it&#8217;ll actually&#8230; you know&#8230; help you out!</p>
<p>And although I bash Lua for not having a type system, it does have a type function for a reason. You can test a variety of types such as assert_not_boolean for a return value that&#8217;s supposed to be a number, and assert_metatable if you&#8217;re doing funky metatable magic.</p>
<p><strong>Suites</strong></p>
<p>A suite is just a series of functions that are related. For example, in my example video I show my file suite which has unit tests for testing my DeleteFileService class and my ReadFileContentsService class. Since reading and writing and deleting files are something I consider related, I created a file suite, or &#8220;a bunch of functions that test file shiz&#8221;.</p>
<p>While lunatest can test functions inline, as an OOP guy, to me that&#8217;s just gross. I like the more organized suites where all the functions are in their own file. Lua calls it a file, I call it a Class, Lunatest calls it a suite&#8230; we&#8217;re all happy.</p>
<p>Here&#8217;s my file one:</p>
<pre lang="lua">module(..., package.seeall)

function test_saveFile()
	require "com.jxl.core.services.ReadFileContentsService"

	local saveFile = SaveFileService:new()
	local data = "moo"
	assert_true(saveFile:saveFile("test.txt", system.DocumentsDirectory, data), "Failed to save test.txt")
end

function test_readFile()
	require "com.jxl.core.services.ReadFileContentsService"
	require "com.jxl.core.services.SaveFileService"

	local saveFile = SaveFileService:new()
	local data = "moo"
	assert_true(saveFile:saveFile("test.txt", system.DocumentsDirectory, data), "Failed to save test.txt for use in reading.")

	local readFile = ReadFileContentsService:new()
	local contents = readFile:readFileContents("test.txt", system.DocumentsDirectory)
	assert_string(contents, "contents are not a string.")
	assert_equal(contents, data, "Data written to file does not match what we just read out of it.")
end</pre>
<p>2 things to note about this file. First, I use the <a href="http://lua-users.org/wiki/LuaModuleFunctionCritiqued">much loathed</a> module(&#8230;, package.seeall) at the top. This is what lunatest wants in how it loads modules so&#8230; you&#8217;ll need to do this too (yes, I temporarily hacked lunatest to support Corona&#8217;s packages, but it wasn&#8217;t worth it).</p>
<p>Second, notice the 2 functions are both global and start with &#8220;test_&#8221;. Any function you want Lunatest to run as a test, you need to prefix it with &#8220;test_&#8221; in the function name. Notice they aren&#8217;t prefixed with local, they&#8217;re simple global functions.</p>
<p>That&#8217;s it. Put a bunch of functions in that file, make an assert or two within them, save it, and then in your main file, tell luna test about it.</p>
<p><strong>Advanced Suites</strong></p>
<p>The above is good enough for writing suites that&#8217;ll help you. Here&#8217;s 4 more cool things suites can do.</p>
<p>If you have repetitive code that needs to be run before every test, you can run it in the test setup. This ensures you only have to run it once, you have the option of aborting the test, and it&#8217;s run in a protected manner (aka <a href="http://www.lua.org/pil/8.4.html">pcall</a>). Additionally, you don&#8217;t have to call this yourself, nor remember to do so, Lunatest does this for you. In my StateMachineSuite, I have to instantiate the StateMachine class for every call so I put it in setup.</p>
<p>If you have code that needs to be cleaned up a lot or in a particular order, you can utilize the teardown. If you implement one, it&#8217;s called after every single test case. This also ensures that if everything is deleted, strange memory bugs are more easily found. Some classes require more than just nilling out their variables, in the case of Corona SDK Display Objects and Widgets which must have their removeSelf called, THEN you can nil out the variable reference. You can also ensure all of the benefits of setup, just in a function called teardown where you clean up your mess.</p>
<p>Finally, there is a suite_setup and a suite_teardown. Unlike setup and teardown, these are only called once for the entire suite; suite_setup before any tests are run, and suite_teardown after everything, including the last teardown, is called. Sometimes you don&#8217;t need unique setup code for your tests so you can put it here instead. This is also a good place for class imports.</p>
<p>Here&#8217;s my StateMachine example. Notice it has a suite_setup (but no suite_teardown). The setup instantiates the StateMachine and the teardown ensures it&#8217;s deleted so each test function gets a brand new SuiteMachine instance.</p>
<pre lang="lua">module(..., package.seeall)

function suite_setup()
	require "com.jxl.core.statemachine.State"
	require "com.jxl.core.statemachine.StateMachine"
	require "com.jxl.core.statemachine.BaseState"
end

function setup()
	machine = StateMachine:new()
end

function teardown()
	machine = nil
end

function test_classWorks()
	assert_not_nil(machine)
end

function test_verifyInitialStateIsNil()
	assert_nil(machine.state)
end

function test_verifyInitialStateIsNullWithStates()
	local initial = "playing"
	machine:addState(initial)
	machine:addState("stopped")
	assert_nil(machine.state)
end

function test_verifyInitialStateIsNotNil()
	local initial = "playing"
	machine:addState(initial)
	machine:addState("stopped")
	machine:setInitialState(initial)
	assert_equal(initial, machine.state)
end

function test_enter()
	local t = {}
	local hitCallback = false
	function t.onPlayingEnter(event)
		assert_equal(event.toState, "playing")
		assert_equal(event.fromState, "idle")
		hitCallback = true
	end
	machine:addState("idle")
	machine:addState("playing", { enter = t.onPlayingEnter, from="*"})
	machine:setInitialState("idle")
	assert_true(machine:canChangeStateTo("playing"), "Not alowed to change to state playing.")
	assert_true(machine:changeState("playing"))
	assert_equal("playing", machine.state)
	assert_true(hitCallback, "Didn't hit the onPlayingEnter callback.")
end

function test_preventInitialOnEnterEvent()
	local t = {}
	local hitCallback = false
	function t.onPlayingEnter(event)
		hitCallback = true
	end
	machine:addState("idle")
	machine:addState("playing", { enter = t.onPlayingEnter, from="*"})
	machine:setInitialState("idle")
	assert_false(hitCallback, "Hit the callback when I had no initial state set.")
end

function test_exit()
	local t = {}
	local hitCallback = false
	function t.onPlayingExit(event)
		hitCallback = true
	end
	machine:addState("idle", {exit = t.onPlayingExit})
	machine:addState("playing", {from="*"})
	machine:setInitialState("idle")
	machine:changeState("playing")
	assert_true(hitCallback, "Never called onPlayingExit.")
end

function test_ensurePathAcceptable()
	machine:addState("prone")
	machine:addState("standing", {from="*"})
	machine:addState("running", {from={"standing"}})
	machine:setInitialState("standing")
	assert_true(machine:changeState("running"), "Failed to ensure correct path.")
end

function test_ensurePathUnacceptable()
	machine:addState("prone")
	machine:addState("standing", {from="*"})
	machine:addState("running", {from={"standing"}})
	machine:setInitialState("prone")
	assert_false(machine:changeState("running"), "Failed to ensure correct path.")
end

function test_hierarchical()
	local t = {}
	local calledonAttack = false
	local calledOnMeleeAttack = false
	function t.onAttack(event)
		calledonAttack = true
	end

	function t.onMeleeAttack(event)
		calledOnMeleeAttack = true
	end

	machine:addState("idle", {from="*"})
	machine:addState("attack",{from = "idle", enter = t.onAttack})
	machine:addState("melee attack", {parent = "attack", from = "attack", enter = t.onMeleeAttack})
	machine:addState("smash",{parent = "melee attack", enter = t.onSmash})
	machine:addState("missle attack",{parent = "attack", enter = onMissle})

	machine:setInitialState("idle")

	assert_true(machine:canChangeStateTo("attack"), "Cannot change to state attack from idle!?")
	assert_false(machine:canChangeStateTo("melee attack"), "Somehow we're allowed to change to melee attack even though we're not in the attack base state.")
	assert_false(machine:changeState("melee attack"), "We're somehow allowed to bypass the attack state and go straigt into the melee attack state.")
	assert_true(machine:changeState("attack"), "We're not allowed to go to the attack state from the idle state?")
	assert_false(machine:canChangeStateTo("attack"), "We're allowed to change to a state we're already in?")
	assert_true(machine:canChangeStateTo("melee attack"), "We're not allowed to go to our child state melee attack from attack?")
	assert_true(machine:changeState("melee attack"), "I don't get it, we're in the parent attack state, why can't we change?")
	assert_true(machine:canChangeStateTo("smash"), "We're not allowed to go to our smash child state from our parent melee attack state?")
	
	assert_true(machine:canChangeStateTo("attack"), "We're not allowed to go back to our parent attack state?")
	assert_true(machine:changeState("smash"), "We're not allowed to actually change state to our smash child state.")
	assert_false(machine:changeState("attack"))
	assert_true(machine:changeState("melee attack"))
	assert_true(machine:canChangeStateTo("attack"))
	assert_true(machine:canChangeStateTo("smash"))
	assert_true(machine:changeState("attack"))
end</pre>
<p>Pay attention to that last part, it has some good and bad practices. The whole point of unit tests is to test 1 thing or unit. You shouldn&#8217;t have 50 billion asserts like I do. Worse, you&#8217;ll notice some of the asserts at the bottom do not have custom error messages in the 3rd parameter. If any 1 of those fail, there is no way to tell which one failed. Bad, Jesse, BAD!</p>
<p><strong>Run</strong></p>
<p>Setting up all of the above is a snap. Ready?</p>
<p>In your main.lua file, import Lunatest:</p>
<pre lang="lua">require "lunatest"</pre>
<p>Next, add your suites:</p>
<pre lang="lua">lunatest.suite("tests.com.jxl.core.ServicesSuite")
lunatest.suite("tests.com.jxl.core.services.ReadFileContentsServiceSuite")
lunatest.suite("tests.com.jxl.core.statemachine.StateMachineSuite")
lunatest.suite("tests.com.jxl.zombiestick.services.LoadLevelServiceTest")</pre>
<p>Finally, call run:</p>
<pre lang="lua">lunatest.run()</pre>
<p>That&#8217;s it! You&#8217;ll see the report of stuff in the console/terminal.</p>
<p><strong>Conclusions</strong></p>
<p>The problem with unit testing is that you need to have units to actually test. A lot of code that wasn&#8217;t written to be unit tested needs to be refactored first which can be a lot of work. If it&#8217;s also entangled with other code that&#8217;s also not easily testable&#8230; you see where this is going. That&#8217;s ok. You can start in one section, or test high level results. Yes, your setup code may be burdensome, but it&#8217;s something. Automated tests, even if a certain section, can help you a lot. Additionally, when writing new code, think about writing it in a way that&#8217;s testable, even if you never actually test it. This often results in less coupled code anyway.</p>
<p>Additionally, while testing is in fact creating more code, you find more bugs, early, and faster, proactively. For games that require quick iterations&#8230; this can be tricky. If the game needs to be built to verify it&#8217;s even fun, is it worth it to unit test? As you make a lot of games in the same tech (whether Lua, C#, ActionScript, Java, whatever&#8230;), you&#8217;ll start to gather are a large set of functions, libraries, and classes that are reusable from project to project. THOSE are worth unit testing.</p>
<p>Unit tests are just a bunch of functions that test expectations, and are organized in suites. You run a bunch of test suites inside of Lunatest. Unit tests help ensure your function types are correct since Lua has no helpful compiler to help on this front as well as spelling mistakes. It also verifies your code works as you expect at runtime. Finally, for larger code bases, you can add new code without worry of breaking old code, including if you modify old code. The more unit tests you write, the more coverage you have. The more coverage, the easier it is to manage a larger code base.</p>
<p>Remember, unit tests are code too. You can still follow all the best practices your used to such as OOP, DRY, and being clean. MOAR UNIT TESTS!</p>
<p><img decoding="async" src="http://jessewarden.com/archives/blogentryimages/lunatest/moar-unit-tests.jpg" /></p>
<p>Title image <a href="http://s4cr4m3nt.deviantart.com/art/Moon-10544945?q=boost%3Apopular%20moon&#038;qo=0">&#8220;Moon&#8221; by S4cr4m3nt</a>.</p>
<p>Also posted on <a href="http://www.ios-gaming.com/2012/07/11/unit-testing-in-corona-sdk-using-lunatest/">iOS Gaming</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://jessewarden.com/2012/07/unit-testing-in-corona-sdk-using-lunatest.html/feed</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
	</channel>
</rss>
