views:

102

answers:

1

I'm currently trying to grasp MSpec, mainly to learn new ways of (T/B)DD to be able to make an educated decision on which technology to use. Previously, I've mostly (read: only) used the built-in MSTest framework with Moq, so BDD is quite new for me.

I'm writing an ASP.NET MVC app, and I want to implement PRG. Last time I did this, I used action filters to export and import ModelState via TempData, so that I could return a RedirectResult and the validation errors would still be there when the user got the view. I tested that scenario by verifying two things:

a) That the ExportModelStateAttribute I had written was applied (among tests for my controller)
b) That the attribute worked (among tests for action filter attributes)

However, in BDD I've understood I should be even more concerned with behavior, and even less with implementation. This means I should probably just verify that the model state is in tempdata when the action has finished executing - not necessarily that it's done via an attribute.

To further complicate things, attributes are not run when calling the action directly in the test, so I can't just call the action and see if the job's been done.

How should I spec/test this in MSpec?

+1  A: 

Filters are cross cutting concerns and as such you should test the behaviour of the filter independently from where it is applied (otherwise you duplicate a lot of testing ).

You can still express the desired behaviour in your controller tests ( model state is stored in temp data ), but the test can assert the existence of the attribute ( could be encapsulated in a a behaviour maybe? ).

As an aside: ASP.NET MVC is designed with the convention of returning the view if the model state contains errors. Using PRG in these scenarios does make sense as PRG is designed to stop duplicate form submission and processing ( i.e. of a valid request ). When a user posts an invalid form, you check for errors before you start processing the request therefore stopping the users request from being processed.

Neal
OK. So basically what you recommend is that I define a behavior that says "stores_model_state_in_temp_data" but actually just checks that the attribute is applied, and then define tests for the attribute in an entirely different test context?
Tomas Lycken
Yes. You test the expected behaviour ( the what ) many times and the implementation of that behiour ( the how ) once.
Neal
OK. Now, a follow up problem: In my old way of testing if an attribute was applied, I used reflection and passed an Expression and a Type to the test method. When specifying a behavior, I can't figure out a way to pass these arguments. (The Type can be figured out by just making the behavior class generic or something, but I still need a lambda...) How do I do that?
Tomas Lycken
In Establish get the MethodInfo of the action you are testing. In Because get the collection of attributes applied using GetCustomAttributes. In the specification assert that the collection should not be zero length.
Neal
Neil is correct. Attributes are cross-cutting concerns, but you can actually test for them via reflection in your BDD context
eduncan911