Guess what, this is what I'm doing right now commenting on the Mehfuz's post. But the main thing I realized reading his post is that this is the perfect example of how using mocks in certain situations can turn testing into a nightmare. The following is not a problem with JustMock, it's a problem with trying to write a unit test involving a complex framework, and isolating parts of it not meant to be isolated.
(Disclaimer: I do understand that the purpose of the original post is not to teach us how to test Asp.Net pages, but to demonstrate the capabilities of JustMock. So, my intent is not to prove that the author is wrong, but rather to take his example as a perfect situation where mock should absolutely not be used.)
So, in order to write the test, we have to
- Mock the HttpBrowserCapabilities class and stub a couple of its properties so that it returns something when needed.
- Mock the HttpRequest class (of course) and make the mock return our mocked Browser.
- Mock the HttpResponse class as well.
- Mock the HttpContext class and stub its Request and Response properties (make the getters return our mock instances).
- Finally, we are stubbing the Page.RenderControl method, and it's unclear whether we do it to avoid exceptions, or just for fun.
Why do we have to mock all these classes? Why do we have to fire up Reflector and dig into the Framework source in order to make our test pass? Because we have this idea that unit testing means testing a particular class in isolation. Somehow all calculator examples left us with an idea that "unit" == "class".
Now, let's back off a bit and consider this: we are testing a high-level ProcessRequest method, which does a lot of lower-level calls to various classes, which are tightly coupled with each other. So, I think it's logical to say that our "unit" is a good part of the System.Web assembly. With that assumption, everything becomes simple: we don't test just our Page instance, we test the whole unit. Assuming we are the developers of the framework, we can also test the lower level methods which have less dependencies, so that we can mock them more easily.
Back to our integration test, here's what it looks like when we use Ivonna. I have omitted all asserts for clarity; instead, we just write messages to the console, as we would in an exploratory test:
This code executes a test against a "real" Web page, with a "real" HttpContext and other necessary objects, so it gives us much more valuable information about the behavior of our system in "real world" situations.[Test] public void TestingPageEvents() { var session = new TestSession(); var request = new WebRequest("Default.aspx"); request.EventHandlers.Page_Init = (sender, e) => Console.WriteLine("Init fired"); request.EventHandlers.Page_Load = (sender, e) => Console.WriteLine("Load fired"); session.ProcessRequest(request); }
Check out a fresh version of Ivonna here.