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.
Outside in Testing of ASP.NET
MVC Applications

Actually that's a lie, but whatever – let's
just do this.
Who am I?
●

I am @robashton

●

I write code (C#,JS,Clojure)

●

I do .NET for pizza + money + love

●

I do JS for just ...
Who are you?
●

You use ASP.NET MVC

●

You want to test stuff

●

●

You're probably working at enterprise
company ACME13...
ASSUMPTIONS
●

You know what a container is

●

You know how ASP.NET MVC works
–

●

Controllers, action filters, model bi...
Let me tell you a story about
every client ever...

@robashton
“We tried to do TDD because
Uncle Bob said so”

@robashton
“We should test trivial code*”

*If you're NASA
@robashton
“We should inject all your
dependencies”

1

@robashton
We should avoid ALL THE
COUPLING*

*Can recommend avoiding coupling ­­>

@robashton
How did that go for you?

@robashton
“We had 100% test
coverage”

@robashton
“Too many tests broke on
changing things”
:(

@robashton
“We spent more time fixing
tests than writing new code”

@robashton
“Our test suite slowed down
our build too much”

@robashton
“We deleted the tests
because they got in our way”

@robashton
No really – every client ever.

@robashton
So, let me say some things...

@robashton
TDD has failed us

@robashton
TDD is not “wrong”, it's just
not always appropriate

@robashton
TDD attempted by a lone
warrior is the Worst Thing
Ever.

@robashton
But that's all okay

@robashton
So... this talk then?
●

This is not a talk about TDD

●

This is a talk about testing

●

That's it.

@robashton
Boom, explosion.

@robashton
You're starting a new project

@robashton
What is it?
●

It is the latest in the line of our
company's own line of unique blue-sky
PRM systems. (Pony Relationship
M...
Where to start?

@robashton
This test is the FIRST THING
you do

@robashton
It is a statement of intent.

@robashton
It's a forcing mechanism.

@robashton
Okay you can do it in C# if
you want

@robashton
Avoid cucumber and
associated foolery
●

●

●

Forced/harmful abstraction
Only useful if non-devs are writing
acceptance c...
So... that test?
●

We need to run some HTTP server

●

We need some sort of browser

●

Anything else...?

@robashton
What are the most important
things about this test?
●

Speed

●

Feedback

@robashton
Right now...
●

●

XSP from the Mono project is good
enough (feel free to play with IIS
express)
PhantomJS is the greatest...
Don't use PhantomJS though
●

Coupling our tests to Phantom is the
worst decision we can make

●

Use WebDriver to drive P...
Testing ASP.NET with
Phantom
WebDriver
HTTP
XSP Web Server

PhantomJS

@robashton

HTTP

Tests
Means we can do this
Firefox
WebDriver
HTTP
XSP Web Server

Chrome

Phantpm

@robashton

HTT
P

Tests
Or this
Firefox
HTTP
XSP Web Server

Chrome

Phantpm

@robashton

WebDriver
HTT
P

HTT
Selenium Grid P

Tests
I write my tests in CoffeeScript

@robashton
I write my contexts in JS

@robashton
I run it all using
●

NodeJS

●

Mocha

●

Mocha-Cakes

●

Should

@robashton
Do it your way
●

It's not important

●

Use whatever

●

C# is fine, I just like JS so I use it

@robashton
A good C# stack
●

NUnit or any other test framework

●

PhantomJS or any WebDriver browser

●

Coypu or any WebDriver cli...
Testing Architecture
System setup/teardown
WebDriver Client

Test code

Client Abstractions (bob)

@robashton
So let's see it in action...

@robashton
A good test
●

Doesn't use CSS selectors

●

Doesn't show implementation details

●

Doesn't have any logic in it

●

Is u...
Instead of

@robashton
Consider

@robashton
Instead of

@robashton
Consider

@robashton
Avoid duplication in your UI
tests
●

●

●

Don't use the same selector more than
once across your contexts
Consider using...
Avoid duplication in your UI
tests
●

Consider using Capybara from Ruby

●

Consider using Coypu from .NET

@robashton
When to drop to the next
level?
●

There are two reasons to drop down a
level

●

“Low level tests are faster”

●

“You ne...
When to drop to the next
level?
●

There are two reasons to drop down a
level

●

“Low level tests are faster”

●

“You ne...
Inverting the test pyramid?

@robashton
“inverting the test pyramid is
not a goal in itself”

@robashton
Times have moved on
●

Focus on speed

●

Focus on reducing effort

●

Focus on increasing feedback

●

Ignore dogma at ev...
Avoid solutions for problems
you haven't got yet
●

●

●

Starting on the outside means you can
change all the details lat...
Example: Defer all the
decisions
●

Let's store some ponies

@robashton
We have a controller

@robashton
How do we store a pony?

@robashton
IHousePonies

@robashton
InMemoryStable

@robashton
Usage

@robashton
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 unt...
SqlStable

@robashton
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...
Example: Avoid layers
●

●

We've chosen to use
RavenDB/NHibernate
We've abstracted this like we were told
to

@robashton
Thin controller – yay!

@robashton
And a thin service!

@robashton
And a thin repository!

@robashton
And a container to wire them
up

@robashton
And tests for each!
­ Controller_can_call_delete_on_the_service.cs
­ Controller_can_call_add_on_the_service.cs
­ Controlle...
Does that feel good?

@robashton
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_de...
What did we learn?
●

●

●

You don't need a container when you
just have one external dependency
You don't need to create...
Avoid writing tests for trivial
code
●

●

●

Controller actions should be trivial
Model binding should be largely
automat...
That said...
●

Drop down to lower level tests for code
with a large number of variants

●

That's things like validation ...
Don't avoid the hard stuff
●

Filters often hide complexity

●

They need testing

●

They often aren't tested

●

They're...
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!...
Example: The hard stuff

@robashton
The test

@robashton
Better to have started with
the test

@robashton
Created code to deal with it

@robashton
And used that in a filter

@robashton
That's (really) it
●

Follow your nose

●

Listen to the pain

●

Focus on the feedback loop

●

Ignore everything I've ju...
Useful things
●

PhantomJS

●

WebDriver

●

Capybara / Coypu

●

Common sense

●

Selenium (not so much)

●

NodeJS/Coffe...
Upcoming SlideShare
Loading in …5
×

Focus on the outside, testing in ASP.NET MVC

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.

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

×