Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Focus on the outside, testing in ASP.NET MVC


Published on

First stab at some talk about testing in microsoft stuffs at enterprise companies without too much experience in TDD etc.

Images are all pilfered from google with no rights, if anybody wants to issue a takedown just ping me and I'll replace them with another.

Published in: Technology

Focus on the outside, testing in ASP.NET MVC

  1. 1. Outside in Testing of ASP.NET MVC Applications Actually that's a lie, but whatever – let's just do this.
  2. 2. Who am I? ● I am @robashton ● I write code (C#,JS,Clojure) ● I do .NET for pizza + money + love ● I do JS for just money + love ● I do Clojure for love. @robashton
  3. 3. Who are you? ● You use ASP.NET MVC ● You want to test stuff ● ● You're probably working at enterprise company ACME1337 Ltd You're after some “real world” comparison @robashton
  4. 4. ASSUMPTIONS ● You know what a container is ● You know how ASP.NET MVC works – ● Controllers, action filters, model binding, etc If I gloss over a definition, either SHOUT AT ME or ignore it as it's probably not important @robashton
  5. 5. Let me tell you a story about every client ever... @robashton
  6. 6. “We tried to do TDD because Uncle Bob said so” @robashton
  7. 7. “We should test trivial code*” *If you're NASA @robashton
  8. 8. “We should inject all your dependencies” 1 @robashton
  9. 9. We should avoid ALL THE COUPLING* *Can recommend avoiding coupling ­­> @robashton
  10. 10. How did that go for you? @robashton
  11. 11. “We had 100% test coverage” @robashton
  12. 12. “Too many tests broke on changing things” :( @robashton
  13. 13. “We spent more time fixing tests than writing new code” @robashton
  14. 14. “Our test suite slowed down our build too much” @robashton
  15. 15. “We deleted the tests because they got in our way” @robashton
  16. 16. No really – every client ever. @robashton
  17. 17. So, let me say some things... @robashton
  18. 18. TDD has failed us @robashton
  19. 19. TDD is not “wrong”, it's just not always appropriate @robashton
  20. 20. TDD attempted by a lone warrior is the Worst Thing Ever. @robashton
  21. 21. But that's all okay @robashton
  22. 22. So... this talk then? ● This is not a talk about TDD ● This is a talk about testing ● That's it. @robashton
  23. 23. Boom, explosion. @robashton
  24. 24. You're starting a new project @robashton
  25. 25. What is it? ● It is the latest in the line of our company's own line of unique blue-sky PRM systems. (Pony Relationship Management) @robashton
  26. 26. Where to start? @robashton
  27. 27. This test is the FIRST THING you do @robashton
  28. 28. It is a statement of intent. @robashton
  29. 29. It's a forcing mechanism. @robashton
  30. 30. Okay you can do it in C# if you want @robashton
  31. 31. Avoid cucumber and associated foolery ● ● ● Forced/harmful abstraction Only useful if non-devs are writing acceptance criteria This is nearly never the case @robashton
  32. 32. So... that test? ● We need to run some HTTP server ● We need some sort of browser ● Anything else...? @robashton
  33. 33. What are the most important things about this test? ● Speed ● Feedback @robashton
  34. 34. Right now... ● ● XSP from the Mono project is good enough (feel free to play with IIS express) PhantomJS is the greatest thing ever. This might not be the case next month @robashton
  35. 35. Don't use PhantomJS though ● Coupling our tests to Phantom is the worst decision we can make ● Use WebDriver to drive Phantom ● Selenium is dead, long live Selenium @robashton
  36. 36. Testing ASP.NET with Phantom WebDriver HTTP XSP Web Server PhantomJS @robashton HTTP Tests
  37. 37. Means we can do this Firefox WebDriver HTTP XSP Web Server Chrome Phantpm @robashton HTT P Tests
  38. 38. Or this Firefox HTTP XSP Web Server Chrome Phantpm @robashton WebDriver HTT P HTT Selenium Grid P Tests
  39. 39. I write my tests in CoffeeScript @robashton
  40. 40. I write my contexts in JS @robashton
  41. 41. I run it all using ● NodeJS ● Mocha ● Mocha-Cakes ● Should @robashton
  42. 42. Do it your way ● It's not important ● Use whatever ● C# is fine, I just like JS so I use it @robashton
  43. 43. A good C# stack ● NUnit or any other test framework ● PhantomJS or any WebDriver browser ● Coypu or any WebDriver client @robashton
  44. 44. Testing Architecture System setup/teardown WebDriver Client Test code Client Abstractions (bob) @robashton
  45. 45. So let's see it in action... @robashton
  46. 46. A good test ● Doesn't use CSS selectors ● Doesn't show implementation details ● Doesn't have any logic in it ● Is understandable for any casual reader @robashton
  47. 47. Instead of @robashton
  48. 48. Consider @robashton
  49. 49. Instead of @robashton
  50. 50. Consider @robashton
  51. 51. Avoid duplication in your UI tests ● ● ● Don't use the same selector more than once across your contexts Consider using conventions across your UI Push everything into your testing model @robashton
  52. 52. Avoid duplication in your UI tests ● Consider using Capybara from Ruby ● Consider using Coypu from .NET @robashton
  53. 53. When to drop to the next level? ● There are two reasons to drop down a level ● “Low level tests are faster” ● “You need more feedback” @robashton
  54. 54. When to drop to the next level? ● There are two reasons to drop down a level ● “Low level tests are faster” ● “You need more fine-grained feedback” @robashton
  55. 55. Inverting the test pyramid? @robashton
  56. 56. “inverting the test pyramid is not a goal in itself” @robashton
  57. 57. Times have moved on ● Focus on speed ● Focus on reducing effort ● Focus on increasing feedback ● Ignore dogma at every level ● Listen to the pain @robashton
  58. 58. Avoid solutions for problems you haven't got yet ● ● ● Starting on the outside means you can change all the details later Don't make decisions about technology until you have to Focus on features and iteration time @robashton
  59. 59. Example: Defer all the decisions ● Let's store some ponies @robashton
  60. 60. We have a controller @robashton
  61. 61. How do we store a pony? @robashton
  62. 62. IHousePonies @robashton
  63. 63. InMemoryStable @robashton
  64. 64. Usage @robashton
  65. 65. This means ● ● ● We end up in an in-memory (fast) system for use in tests We can get on and develop now We can wait until we know what we need before choosing something @robashton
  66. 66. SqlStable @robashton
  67. 67. Not for the sake of it ● ● If you're using RavenDB it's got an inmemory built in If you're using Redis, it's fast enough “What's it going to cost vs what we're going to gain” @robashton
  68. 68. Example: Avoid layers ● ● We've chosen to use RavenDB/NHibernate We've abstracted this like we were told to @robashton
  69. 69. Thin controller – yay! @robashton
  70. 70. And a thin service! @robashton
  71. 71. And a thin repository! @robashton
  72. 72. And a container to wire them up @robashton
  73. 73. And tests for each! ­ Controller_can_call_delete_on_the_service.cs ­ Controller_can_call_add_on_the_service.cs ­ Controller_can_call_get_on_the_service.cs ­ Controller_will_return_a_view_model_from_the_service.cs ­ Service_will_call_delete_on_the_data.cs ­ Service_will_call_add_on_the_data.cs ­ Service_will_call_get_on_the_data.cs ­ Service_will_return_a_pony.cs ­ Sevice_will_return_null_when_there_is_no_pony ­ Data_will_persist_a_pony.cs ­ Data_will_delete_a_pony.cs :( ­ etc @robashton
  74. 74. Does that feel good? @robashton
  75. 75. With Saving_a_pony_will_result_in_a_pony_existing.cs A_pony_can_be_displayed_to_our_lovely_user.cs A_pony_can_sadly_be_deleted_oh_how_sad.cs @robashton
  76. 76. What did we learn? ● ● ● You don't need a container when you just have one external dependency You don't need to create interfaces and classes all over the show Let these things emerge if the complexity dictates it @robashton
  77. 77. Avoid writing tests for trivial code ● ● ● Controller actions should be trivial Model binding should be largely automatic It'll make you feel good, but that's about it @robashton
  78. 78. That said... ● Drop down to lower level tests for code with a large number of variants ● That's things like validation rules ● That's things like domain logic @robashton
  79. 79. Don't avoid the hard stuff ● Filters often hide complexity ● They need testing ● They often aren't tested ● They're often brittle! @robashton
  80. 80. The hard stuff ● Test-drive the code for the actual logic ● Then bring it in to ASP.NET MVC ● Don't mock ASP.NET MVC!! @robashton
  81. 81. Example: The hard stuff @robashton
  82. 82. The test @robashton
  83. 83. Better to have started with the test @robashton
  84. 84. Created code to deal with it @robashton
  85. 85. And used that in a filter @robashton
  86. 86. That's (really) it ● Follow your nose ● Listen to the pain ● Focus on the feedback loop ● Ignore everything I've just said @robashton
  87. 87. Useful things ● PhantomJS ● WebDriver ● Capybara / Coypu ● Common sense ● Selenium (not so much) ● NodeJS/Coffeescript/Mocha/Mocha-Cakes @robashton