Unit Testing for startups<br />Experiences from Loopt<br />
Heine Frifeldt <heine@loopt.com><br /><ul><li>Server Team Manager
Got Introduced to extreme programming in 2000 @ Adomo DK
Have previously tried to have lots of manual tests
Realized the value of unit tests
Continued Agile Development in Adomo US
Joined Loopt in 2008
Code examples are in C#, but topics should apply regardless of language
Feel free to ask questions</li></ul>2<br />
Loopt – What do we do?<br />3<br />Connecting You with Friends and Family<br />
Loopt – What do we do?<br />4<br />Connecting You with the Places You Go<br />
Loopt – What do we do?<br />5<br />Connecting You with Your Local Businesses<br />
Time for Unit Test in Startup?<br /><ul><li>Turn one-off tests into automated tests
Takes extra time upfront but it’s worth it
Legacy clients likely for mobile companies
Confident deployments
Unit tests work as documentation
Easy way for new employees to get familiarized with code</li></ul>6<br />
Overview<br /><ul><li>Initial state of Loopt tests
Untestable code
Code structure
Improved code
Lessons learned
Tools</li></ul>7<br />
Initial Experience<br /><ul><li>My first UT experiences we wrote the tests along with code
You structure your code for testability
Upcoming SlideShare
Loading in...5
×

Loopt unit test experiences

1,467

Published on

We all hear how unit tests can ensure higher quality code and help us in day to day refactoring, but is it feasible to write and maintain unit tests in a fast paced startup company?

This is a presentation by server lead, Heine Frifeldt, on how unit tests was gradually introduced into the server code base at Loopt, which tools are used in the continuous build environment, coding techniques and lessons learned.

Published in: Technology, Education
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
1,467
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
10
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide
  • No constructorStatic method to execute logicMakes connection to DB and invokes stored procReads from binary stream and converts to storecproc arguments
  • Notice ConfigurationManager.GetSection is a static from BCLSome code paths would check “IsProduction” config setting and behave according to environment
  • Loopt unit test experiences

    1. 1. Unit Testing for startups<br />Experiences from Loopt<br />
    2. 2. Heine Frifeldt <heine@loopt.com><br /><ul><li>Server Team Manager
    3. 3. Got Introduced to extreme programming in 2000 @ Adomo DK
    4. 4. Have previously tried to have lots of manual tests
    5. 5. Realized the value of unit tests
    6. 6. Continued Agile Development in Adomo US
    7. 7. Joined Loopt in 2008
    8. 8. Code examples are in C#, but topics should apply regardless of language
    9. 9. Feel free to ask questions</li></ul>2<br />
    10. 10. Loopt – What do we do?<br />3<br />Connecting You with Friends and Family<br />
    11. 11. Loopt – What do we do?<br />4<br />Connecting You with the Places You Go<br />
    12. 12. Loopt – What do we do?<br />5<br />Connecting You with Your Local Businesses<br />
    13. 13. Time for Unit Test in Startup?<br /><ul><li>Turn one-off tests into automated tests
    14. 14. Takes extra time upfront but it’s worth it
    15. 15. Legacy clients likely for mobile companies
    16. 16. Confident deployments
    17. 17. Unit tests work as documentation
    18. 18. Easy way for new employees to get familiarized with code</li></ul>6<br />
    19. 19. Overview<br /><ul><li>Initial state of Loopt tests
    20. 20. Untestable code
    21. 21. Code structure
    22. 22. Improved code
    23. 23. Lessons learned
    24. 24. Tools</li></ul>7<br />
    25. 25. Initial Experience<br /><ul><li>My first UT experiences we wrote the tests along with code
    26. 26. You structure your code for testability
    27. 27. Adding tests for existing code can be much harder
    28. 28. Believe common startup problem
    29. 29. You get to a point where you realize it would be nice with unit tests</li></ul>8<br />
    30. 30. Unit Tests at Loopt<br /><ul><li>General support behind Unit Test
    31. 31. Most eng. wanted to add unit tests, but it was hard, so in practice new tests were rarely added
    32. 32. VPE had previous good experiences with unit tests and our deployment did not have good track record
    33. 33. The existing tests were neglected
    34. 34. One test project for all projects
    35. 35. Few tests
    36. 36. End to end functional tests
    37. 37. Complex architecture and code that requires mobile to invoke</li></ul>9<br />
    38. 38. Code Example (Database Access Layer)<br /><ul><li>One of my first tasks was to add a LockedOut property to our User class
    39. 39. In theory to test it, Initialize LooptUser, Emulate failed login N times, Verify field got set
    40. 40. In practice
    41. 41. Constructor takes phone number (or session, or …) which reads and sets all relevant properties directly from DB
    42. 42. Login is a static method in a different class which makes direct DB calls
    43. 43. Checks your phone make/model
    44. 44. Makes external billing checks to certain carriers</li></ul>10<br />
    45. 45. Code Example (Business Logic)<br /><ul><li>Loopt Cell Server takes binary stream from clients and processes request
    46. 46. Stream passed down through the flow – and maybe modified
    47. 47. Some tests used the raw binary stream to verify functionality</li></ul>11<br />
    48. 48. Code Example (Business Logic)<br />public class DeleteJournal{<br /> private DeleteJournal() {}<br />public static void ProcessRequest(byte[] content) <br /> { <br /> using (SqlData sdp = new SqlData("sp_Delete_Journal")) <br /> {<br /> byte deltype = content[pos++];<br /> byte num = content[pos++]; <br /> entry = BitUtil.ReadInt(content, ref pos);<br />sdp.AddParameter("@EntryID", SqlDbType.Int, entry);<br /> […]<br />12<br />
    49. 49. Code Example (Static Initializers)<br /><ul><li>Carrier class has internal constructor
    50. 50. Get it from carrier factory
    51. 51. Has static initializer which reads carrier settings from a config file</li></ul>static CarrierFactory() <br />{<br />SmppMap = new Dictionary<string, SmppConnectionElement>();<br />CarrierSettings configSection = <br /> (CarrierSettings)ConfigurationManager.GetSection("carriers"); <br />foreach (SmppElemtn sce in configSection.SmppConnectionElements) <br /> {<br />[…]<br />13<br />
    52. 52. Argh!!<br /><ul><li>Ways of testing suggested to me
    53. 53. LooptUser - Create a test account and use number and password in tests
    54. 54. CellServer - Manual test with real phone
    55. 55. Carrier - Use phone number of wanted carrier
    56. 56. Manually create test data
    57. 57. Didn’t know what to change and where to begin and end</li></ul>14<br />
    58. 58. Testable Code Talk<br /><ul><li>Hosted unit test talks about testable code
    59. 59. MiskoHevery@ Google
    60. 60. http://misko.hevery.com/2008/11/11/clean-code-talks-dependency-injection
    61. 61. Key points
    62. 62. Avoid use of statics (your own and base class libraries)
    63. 63. Keep constructors simple - they cannot be overridden.
    64. 64. Separate object graph from logic – remove new operators
    65. 65. Ask for what you need (dependency injection) and have DI framework to initialize root objects
    66. 66. Hollywood Principle</li></ul>15<br />
    67. 67. Improvements<br /><ul><li>Immediate steps (no tools)
    68. 68. Start using dependency injection in new code
    69. 69. Refactor existing code when changes are required
    70. 70. Use our own BuildObject initializers
    71. 71. Use our own mock object implementations for testing
    72. 72. After ~6 months
    73. 73. Core code was more nicely structured
    74. 74. Unit tests and root objects were cluttering up with object graph initializations
    75. 75. Starting using Ninject
    76. 76. After ~2 years
    77. 77. Got Moq demoed. Just started using that.</li></ul>16<br />
    78. 78. Example Class using Dependency Injection<br />public class GrouponAdapter : IGrouponAdapter<br />{<br /> private readonly IPoiController _poiController;<br />private readonly DataContextProvider _contextProvider;<br />private readonly ILooptWebClient _looptWebClient;<br /> [Inject]<br />public GrouponAdapter(IPoiController poiController, DataContextProvider contextProvider,  ILooptWebClient looptWebClient) <br />{<br /> _poiController = poiController; _contextProvider = contextProvider; _looptWebClient = looptWebClient; <br />}<br />…<br />17<br />
    79. 79. Example Ninject Bindings<br />public class LooptLogicModule : NinjectModule<br />{<br />public override void Load() <br /> {<br /> Bind<IPoiController>().To<PoiController>().InSingletonScope(); Bind<ILooptWebClient>().To<LooptWebClient>().InSingletonScope();<br /> … <br />private IKernel _kernel;<br />_kernel.Get<IGrouponAdapter>();<br />18<br />
    80. 80. Example Unit Test using Moq<br />[TestMethod]<br />public void ParseGrouponDeals()<br />{<br />// Results in 6 deals being returned.<br />var webClient = new Mock<ILooptWebClient>();<br />webClient.Setup(c => c.DownloadString(It.IsAny<Uri>())).<br /> Returns(Resources.Groupon_Deals_In_Austin);<br />IGrouponAdapter ga = new GrouponAdapter(null, webClient.Object);<br />Deal[] deals = ga.GrouponDeals(new Coordinate(30.44595, -97.79016)); <br />Assert.AreEqual(6, deals.Length, "Expected 6 deals");<br />}<br /> <br />19<br />
    81. 81. Lessons Learned - Test Barriers<br /><ul><li>Hook up Ninject immediately in new projects
    82. 82. New operators can quickly creep back in
    83. 83. Add helpers when “impossible” or impractical to change
    84. 84. Use IDispose interface for TransientXXXXX test classes
    85. 85. Users
    86. 86. Phone numbers
    87. 87. Carriers
    88. 88. Config files
    89. 89. Non-ideal tests are better than no tests
    90. 90. Well, usually ;-)</li></ul>20<br />
    91. 91. Lessons Learned – Adding Tests<br /><ul><li>No strict test requirements; test can be written up front or after
    92. 92. Tests added later are better than no tests
    93. 93. Add tests when you encounter a bug
    94. 94. Bookmark/revisit hard to test code and set goal to write one test
    95. 95. Restructure / helpers will result in many more tests
    96. 96. Tools can be introduced gradually
    97. 97. Introduce DI from top to bottom to avoid cascading changes</li></ul>21<br />
    98. 98. Current Tools<br /><ul><li>Source Control - Mercurial
    99. 99. Unit Test Framework – Visual Studio
    100. 100. Automated Build Environment - Jenkins
    101. 101. Code style – Dependency Injection
    102. 102. Dependency Injection Framework - Ninject
    103. 103. Mock Framework - Moq</li></ul>22<br />
    104. 104. State of our tests<br /><ul><li>34 Test Projects
    105. 105. 1008 Unit Tests. Executed on commit. Takes ~10 min
    106. 106. 23 Functional tests. Executed nightly. Takes ~1 min
    107. 107. Too long execution time
    108. 108. Flaky tests tend to put us into bad streaks of several days with failing tests
    109. 109. Due to timing
    110. 110. Due to functional test nature</li></ul>23<br />
    111. 111. Jenkins (aka Hudson)<br /><ul><li>Nice overview of projects of their state
    112. 112. Age of failing unit tests
    113. 113. Execution time of unit tests</li></ul>24<br />
    114. 114. Next steps<br /><ul><li>Continue refactoring existing code to use DI/Ninject
    115. 115. Refactor existing tests to be more unit and less functional test
    116. 116. Faster
    117. 117. Not flaky
    118. 118. Better process for dealing with broken tests in crunch mode
    119. 119. Don’t want to ignore false negatives
    120. 120. Don’t notice new failures
    121. 121. Wait for better Ninject integration with ASP.NET, MVC, WCF, NT Services.</li></ul>25<br />
    122. 122. We are hiring ($5000 referral bonus)<br /><ul><li>System Administrator
    123. 123. Build Engineer
    124. 124. Metrics Engineer
    125. 125. Multiple QA
    126. 126. Server
    127. 127. iPhone
    128. 128. Android
    129. 129. Web</li></ul>26<br />
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×