Technical

June 03, 2008

Composite Views in Model-View-Presenter

There was a lively discussion on the ALT.NET mailing list about composite views when doing Model-View-Presenter, and how the sub-views get exposed. I shared my view (no pun intended) on the different strategies you might employ for sub-views.

Generally speaking, when doing Model-View-Presenter, the view is the thing that is addressable from the outside world. For example, when doing MVP with WebForms, the URL that you issue GET and POST requests against usually resolves to a View (in this case, a .aspx page). Of course, in Separated Presentation (which MVP is one form of), we want our views to be as dumb as is reasonable. Since the View is the addressable element, we often say that the Presenter is an "implementation detail" of the View. This means that the outside world is interacting with the View, and the view forwards those details onto the Presenter to do with what it will.

Many View engines support the idea of sub-Views. In WebForms, for instance, this takes the form of both User and Server Controls. A View (especially a top level View like a Page in WebForms) is usually a Composite View.

How are sub-Views handled with Model-View-Presenter? The answer probably depends on what form of MVP you're doing.

Sub-Views in Supervising Controller

Supervising Controller is the probably the more common form of MVP. The Presenter acts as an intermediary between the Model and the View, and the View contains some logic which breaks apart Model elements and places them into UI pieces on the screen.

The easiest approach to supporting sub-views has the Composite View delegating to the sub-Views without its Presenter's knowledge. As far as the Presenter is concerned, the Composite View is the only view. It passes the data into the View, and the View does with it whatever is necessary.

Most ASP.NET WebForms apps already do this, but it's not a conscious activity. Each one of those controls that you're using is a View, whether it has a Presenter or not. In fact, you don't know whether they're implemented with MVP or not, because the Presenter is, as it should be, an implementation detail. The View offers an API to you, and you use it, and trust it to do the necessary work.

When you start thinking about writing your own sub-Views, it's natural to fall into this pattern, because it's generally how the system is designed to work. The only difference is, you know there is a Presenter behind the View, just because you wrote them both. Refactoring will often lead you into this delegation pattern as well, because you're only changing the View, and not the underlying Presenter.

On the web, the main difference between your top-level View and sub-Views will often be the way you get data. On the web, the top-level View gets data from the HTTP request (URL, query parameters, form data, etc.), but sub-Views often get direct data from their consumers (strings, structured objects, etc.).

For GUI applications, there's often no difference in the way data passes between top-level Views and sub-Views, since there isn't an outside-world mechanism like HTTP.

Alternative Style: Expose Sub-Views

Although I personally prefer the approach outlined above, one alternative would be to expose your sub-Views directly off of the Composite View. When practicing MVP, most people create an interface for the View which the Presenter talks to. The Composite View can expose these view interfaces directly to its Presenter, and allow the Presenter to talk directly to the sub-Views. In turn, those sub-Views will pass on their data to their own Presenter.

The benefit here is that you may be able to factor out common Presenter behavior and actually create Composite Presenters to go along with your Composite Views, as a way of achieving DRY. The downside, though, is that you've created a tighter coupling; not only is the Presenter for the Composite View aware of that View, but also of all the sub-Views that it uses. This has the effect of reducing the refactorability of the code.

Sub-Views in Passive View

Passive View style MVP is less common than Supervising Controller, although it is the style I personally prefer. The idea behind Passive View is to eliminate all code from the View, even code that would normally have been responsible for breaking apart model data and placing onto the screen.

In this style of MVP, the View is essentially directly always exposing all sub-Views, and the Presenter is directly setting values into the Views (and subscribing to notifications from them).

A sub-View here usually ends up getting re-exposed by the Composite View. For example, if you had an address editor on screen, you would probably expose text boxes for the 2 lines of address, the city, the state, and the postal code. While these things may be represented as a sub-View, their individual elements are re-exposed by the Composite View as though they were on the Composite View itself. When you re-use the sub-View (say, to edit both a shipping address as well as a billing address), the Presenter is still directly exposed all the text boxes, though they may now have names like ShippingAddress1, ShippingAddress2, BillingAddress1, BillingAddress2, etc.

May 30, 2008

Mocking Still Not Quite There For Me

The release of Moq (and the subsequent updating of Rhino Mocks in response) has made mock frameworks much more approachable to me, but I still find situations where hand-rolled stubs seem to work best.

Wednesday, Jim and I were trying to see what it might look like if we replaced our stubs with a mocking framework. We have two interfaces which we are hand stubbing today:

  public interface ITestCommand
  {
    string Name { get; }
    bool ShouldCreateInstance { get; }

    MethodResult Execute(object testClass);
  }

  public interface ITestClassCommand
  {
    object ObjectUnderTest { get; }
    ITypeInfo TypeUnderTest { get; set; }

    int ChooseNextTest(ICollection testsLeftToRun);
    Exception ClassFinish();
    Exception ClassStart();
    IEnumerable<ITestCommand> EnumerateTestCommands(IMethodInfo testMethod);
    IEnumerable<IMethodInfo> EnumerateTestMethods();
    bool IsTestMethod(IMethodInfo testMethod);
  }

A quick background on some of the types involved here:

  • ITestClassCommand represents a “class with tests”. It’s used by the execution engine when running the tests. Most of what’s used there isn’t important, but what is important for this test is EnumerateTestCommands().
  • ITestCommand represents a “single execution of a test”. Each test method may yield multiple executions (think data-driven testing), which is why ITestClassCommand.EnumerateTestCommands() returns a collection of these rather than just one.
  • IMethodInfo is an abstraction of the CLR’s MethodInfo class, which is necessary because sometimes when you’re being asked to enumerate these things, you don’t actually have a real MethodInfo (f.e., when ReSharper is asking you to tell it what tests exist in the source file that user is looking at).

The actual class under test is TestCommandFactory. Its single responsibility is: given a ITestClassCommand instance and a MethodInfo, generate the ITestCommand instances to run all the tests. It does more than just get the instances from the class command: it wraps them using the chain of responsibility pattern to provide all the extra work that goes into running and reporting on a test command, which includes:

  • Running all the BeforeAfterAttributes found decorating the test method
  • Creating a new instance of the type under test (if the inner ITestCommand.ShouldCreateInstance is true)
  • Turning Trace.Fail and Debug.Fail statements into thrown exceptions
  • Catching exceptions thrown by the test and turning them into FailResult objects
  • Timing how long it takes to run the class

As you can see, the presence and absence of these things is important, and order is also important. Our hand-rolled stubs record the values that were passed in, and allow you to control values that were returned. Our test, in pseudo-code, is approximately:

Arrange:

Create a stub of ITestCommand (stubTestCmd)

- In response to ShouldCreateInstance, return true

Create a stub of ITestClassCommand (stubClassCmd)

- In response to EnumerateTestCommands, return StubTestCmd

Get the MethodInfo for an empty, void-returning method (methInfo)

Act:

Call TestCommandFactory.Make, passing stubClassCmd and methInfo

Assert:

Ensure that the IMethodInfo passed into stubClassCmd.EnumerateTestMethod wrapped methInfo

Ensure that we returned a wrapped ITestCommand (test all the levels of wrapping described above)

Because our stubs record the passed-in values and we can inspect them, our first assertion is easy to write:

  Assert.Same(methInfo, stubClassCmd.EnumerateTestCommands_TestMethod.MethodInfo);

Note that we’re not just testing the value (that would be stubClassCmd.EnumerateTestCommands_TestMethod) but we’re actually diving into it and testing a specific value (.MethodInfo). This is because ITestClassCommand takes an IMethodInfo, but we actually pass a MethodInfo to the method under test.

When we tried to convert this to Moq, we were stuck. We could make a Mock<ITestClassCommand>, but we could neither specify (via .Expect) nor verify (via .Verify) against the data item it recorded. We actually need the actual value; the wrapper isn’t important, but what it wrapped was.

We found a way to write the test, which was to cascade a .Callback after the .Expect and do the assertion. However, this put assert logic up inside our arrange. Alternately, we could’ve stashed the value into a temporary and did the assertion afterwards, but that made things start to feel a little unwieldy compared to the hand-rolled stubs.

We also found the use of “Expect” to be unfortunate, particularly the syntax that we ended up with (approximately):

  var mockClassCommand = new Mock<ITestClassCommand>;
  mockClassCommand.Expect(x => x.EnumerateTestCommands(It.IsAny<IMethodInfo>()))
                  .Returns(new List(mockTestCmd));

Our problem is with the monstrosity of “It.IsAny<IMethodInfo>()”. It looks bad enough with a single parameter, but would look positively awful with several parameters. The truth is that I rarely want to say “if given A, return B”; I almost always say “return B, and I’ll verify in the Assert that I was passed A”. This would be a much better syntax:

  var mockClassCommand = new Mock<ITestClassCommand>;
  mockClassCommand.Stub(x => x.EnumerateTestCommands).Returns(new List(mockTestCmd));

The compiler error I get from this tells me that the Lambda system in C# 3 probably won’t ever let me get to this kind of a syntax. I’m also not even sure about what the syntax would look like that lets me inspect the executions of each call to EnumerateTestCommands, so that I could ensure it was only called once and that the wrapper wrapped the right thing.

I think Wednesday we came to the realization that a code generator was probably what we were going to end up with. I’ve come around several times to the problem and, even after seeing Lambdas in C# 3, concluded that a generator which could creates stubs of any interface/abstract class is still the ideal situation.

May 28, 2008

xUnit.net 1.0.1 Released

We just shipped xUnit.net 1.0.1 today. Aside from a handful of bug fixes, the two major things addressed for this release are:

  • Support for ASP.NET MVC Preview 3 (released yesterday)
  • Support for newer builds of F#

Enjoy!

May 13, 2008

The Past, Present, and Future of .NET Unit Testing

If this feels like a repeat, then you might be living in that cool Star Trek: TNG episode where the ship blows up in the teaser! Or, it might be that the show's actually available now. :)

At the ALT.NET conference in Seattle last month, Scott Hanselman said he wanted to use the opportunity of all these people being physically together to do some unique podcasts. On my way off to party after the end of Saturday's talks, I received a phone call asking me to come back so we can do a "quick" podcast with all the .NET unit testing framework people. (Note to Future Brad: Hanselman's "it'll only take 20 minutes" means an hour, at least :) ).

The result was an interesting discussion about the evolution of unit testing on the .NET platform. I was there to represent xUnit.net; Charlie Poole was there to talk about NUnit; Jeff Brown was there to tell us about MbUnit and the Gallio test runner; and Roy Osherove was there discussing unit testing in general and the book he's writing, "The Art of Unit Testing".

April 23, 2008

xUnit.net 1.0 Released

We released xUnit.net 1.0 RTM today.

Acknowledgements

Many people have helped us get to our 1.0 release.

First, we want to acknowledge the inventors of the core ideas behind xUnit frameworks, especially Kent Beck and Eric Gamma, without whom we probably wouldn't have anything to talk about today. :)

Second, we want to thank the people who hatched the idea of a new framework with us, including Peter Provost, Brian Button, Scott Densmore, Jonathan Wanagel, Jamie Cansdale, and Drew Miller.

Lastly, our community provided significant feedback to us during the development process by providing feedback on the web site, opening feature requests, reporting bugs, and generally helping guide the design of the framework. We especially want to thank Matt Podwysocki, Ben Hall, Harry Pierson, Scott Hanselman, Kirk Viehland, Daniel Cazzulino, Oren Eini, Jeff Brown, and Charlie Poole.

Looking Back

We release Beta 1 of our framework September 19, 2007, almost exactly 7 months ago. It took a lot longer than we thought it would to get to 1.0, especially given that we had been using the framework extensively internally for a while before that.

Our original release plans called for just a console runner, but our users quickly educated us on the value of variety. We personally are TestDriven.net users, so that became our second runner; our community quickly followed on asking us to support ReSharper and to write a stand-alone GUI runner. Our time spent with the console runner in an automated environment then drove us to write an MSBuild task which provides much better feedback on the testing process.

Extensibility was a very important feature for us. We felt that there was a lot to be desired in the landscape of extensibility for test frameworks. An important early decision we made was to push as much of our "functionality" as we possibly could out into extensions so that we were forced to exercise and improve our extensibility points.

Another unexpected issue was around test runners and their tight coupling to the version of xUnit.net that they were built against. We made a decision to push out the 1.0 release in order to better support the idea of having test runners that were independent from any specific version of xUnit.net. We succeeded for all of our runners, save the ReSharper runner, for reasons we've already documented.

Looking Forward

Our near-term focus is going to be on refining the process of actually using the framework for Test Driven Development, especially in conjunction with Visual Studio. While tools like TestDriven.net provide a lower friction environment than others, we still believe that there is room for improvement in the day to day usage for TDD.

A lot of this work will be centered around the GUI runner. What we released in 1.0 is essentially a bare-bones runner that we labeled experimental. While we would like to know if you have issues with the runner, please be aware that we are intended to make dramatic changes to it to help support our idea of zero-friction TDD.

It is our intention, therefore, to release interim drops of the GUI runner as we make progress, hopefully on a fairly regular schedule.

Additionally, there are several releases on the horizon (especially ReSharper 4.0 and ASP.NET MVC) which will likely also result in new point releases of the framework.

For the longer term (version 2.0), what we really want now is to let the framework get greater adoption so that many more users can help provide feedback on the things they love and the things they don't, the things that just work and the things that could be tweaked. If you download and use 1.0, please visit our forums and tell us about your experiences!

April 14, 2008

Small Decisions Sometimes Cause Big Hacks

When .NET was being designed and introduced, it was notable not only in the ways in which it “borrowed” from Java, but also in the ways in which it parted from it. Some decisions were obviously good (dumping checked exceptions comes to mind) while some were clearly troubling (non-virtual methods by default).

Some, though, seemed insignificant at the time until you come up against them. Today’s example:

When is the stack trace for an exception generated?

In Java, the stack trace is generated when an exception is created, and in .NET it’s generated when the exception is thrown. In practical terms, with 99% of throws looking like this, it hardly matters:

throw new SomeException();

The creation and the throw actually happen on the same line of code. The stack trace is identical in both cases.

However, this seemingly small decision has rippling impact throughout the framework and languages. How many times have you seen this code and cringed?

catch(Exception ex)
{
    DoSomething();
    throw ex;
}

We’ve all seen it. That “throw ex” line destroys the original stack trace and replaces it with your own. The C# language team even had to invent a way to “re-throw an exception without destroying the original stack trace”, which is “throw;” on a line all by itself.

This probably should’ve been the clue that the wrong decision was made.

It’s reasonable to think that there might be a time when you have an exception object, outside of a catch block, and you want to re-throw that exception as though it were never caught. In fact, the framework team themselves came across just such a situation and invented their own hack to handle it, and built it into the Exception class.

When you are talking to a class via remoting, an exception thrown by the remote component is caught by the remote end and serialized back to the transparent proxy. The transparent proxy (which is what the client code is talking to) needs to experience that exception just as though it had been thrown locally. The problem is, we’re not in a catch block; we have a hydrated exception, but need to re-throw it without trashing the stack trace.

There is a private field inside of Exception into which you can stuff a stack trace which says “when I throw you, this is your stack trace; don’t make a new one”. This sample helper method shows you how to do the work:

public static void RethrowWithNoStackTraceLoss(Exception ex)
{
    FieldInfo remoteStackTraceString =
        typeof(Exception).GetField("_remoteStackTraceString",
                                   BindingFlags.Instance | BindingFlags.NonPublic);
    remoteStackTraceString.SetValue(ex, ex.StackTrace);
    throw ex;
}

I first ran across this trick via Peter Provost pointing me to Chris Taylor’s blog post on the subject. I’ve used it several times now (in ObjectBuilder and xUnit.net), and I’m thankful for it every time I run across it.

Since we’re talking about exceptions…

One of my biggest gripes about exceptions relates to reflection. The remoting team obviously went to great lengths to hide the fact that you were talking to a transparent proxy instead of the real object. That’s really the whole reason this hack exists in the first place. You can treat a transparent proxy just like the real thing.

It’s not so easy with Reflection. If you invoke something through reflection, and it throws an exception, the reflection infrastructure catches that exception and wraps it in TargetInvocationException. It’s basically an “I was here!” exception: the thing you actually care about it partially obscured by it. Nobody ever really cares about TargetInvocationException; it’s just a reminder that you’re doing things differently than normal, and you can’t treat some thing like you normally would.

I use this re-throw trick when reflection is an unimportant implementation detail (which it almost always is). For example, when running a test in xUnit.net, the test method is invoked via reflection; the person writing the test shouldn’t ever care about that detail. If every exception that was thrown in a test was reported as a TargetInvocationException, I’m pretty sure people would be telling us it was a bug.

So our implementation of TestCommand.Execute() uses this code instead:

public MethodResult Execute(object testClass)
{
    try
    {
        testMethod.Invoke(testClass, null);
    }
    catch (TargetInvocationException ex)
    {
        ExceptionUtility.RethrowWithNoStackTraceLoss(ex.InnerException);
    }

    return new PassedResult(testMethod, Parameters);
}

We originally spun in a loop at the point where we caught exceptions and turned them into FailedResult, stripping off any TargetInvocationExceptions that were contained. But that made testing for TargetInvocationException difficult in some cases, because you couldn’t differentiate between a TargetInvocationException you didn’t care about from one you did.

As such, everywhere that we use reflection, you’ll find a try/catch like this, eradicating the less-than-useless TargetInvocationException from the exception stack. Every time we have to write it, it makes me wish the reflection team had just done the right thing in the first place.

April 10, 2008

xUnit.net 1.0 RC3 Released Today

We've finally finished off all the work we wanted to achieve with the version-independent runner support, so we cut a new release candidate today. There were a few bugs fixed, and we added support for CruiseControl.net and ASP.NET MVC Preview 2, but otherwise this release should function more or less like the RC2 Refresh.

We believe we are now v1 feature complete.

At this point, we will only be fixing critical bugs. We're especially looking for feedback from runner authors on the functionality of ExecutorWrapper. If you're looking for examples on how to use ExecutorWrapper, the best places to start are the source code for the MSBuild task and the unit tests, although all the runners (except the Resharper runner, as I talked about yesterday) are using ExecutorWrapper now. In fact, all of our dynamic-compilation acceptance tests are also use ExecutorWrapper.

Barring any major bugs found, we're planning to release v1 at the end of the month.

April 09, 2008

xUnit.net's Resharper Runner - No Version Independence

Our version independent runner scheme has served us well so far: all of our runners have converted over to it except for the Resharper runner. Jim and I intended to tackle the Resharper runner today and make it version independent as well, but ran into some stumbling blocks that caused us to postpone the work indefinitely.

The API for the version independent runners is relatively simple, and everything is communicated in terms of simple strings and XML. I explained a bit about it in my previous post about RC2, so I won't re-cover old ground.

The problem with Resharper that's different from all the other runners is that it operates in a mode where there is no assembly file. You are asked to answer questions about whether classes contain tests based on the source code that's in the editor, not the bits that are on the disk. This makes perfect sense: they want to provide "run this" chicklets as soon as you add a test to your assembly.

Unfortunately, our API is based on assemblies on the disk. Most of the decision making is done on your behalf; you're just asking to run assemblies, classes, or tests based on filenames and fully qualified type and method names.

In order to support Resharper, we would essentially have to serialize (potentially incomplete) type information into XML and pass it across an app domain boundary to get it inspected in order to make decisions about whether something is a test or not. Aside from the obvious performance implications, we were also concerned with the tremendous complexity it would introduce for essentially one runner. There were also issues about how to properly locate the xunit.dll that they would eventually be linking against.

In the end, we decided it wasn't going to happen.

Unfortunately, this means that the Resharper runner is going to suffer from version dependence, so you'll only ever be able to test against one version of xunit.dll with Resharper (whichever version the Resharper support was installed with).

Users who want integrated Visual Studio test runner capabilities with version independence are encouraged to use TestDriven.net.

P.S. Only Resharper 3.1 is currently supported. We won't be supporting 4.0 until the final RTM. Sorry for the inconvenience.

Upcoming Events

Man, the time has flown by! I can't believe it's almost Tax Day.

Next weekend (Fri April 18 through Sun April 20) I'll be hanging out at DigiPen for the ALT.NET Seattle event. Since this event was purposefully timed to coincide with the MVP Summit next week, I imagine I'll be out and about meeting up with people during the week prior; if you're in town and want to hang out, my e-mail is bradwils at microsoft.

The P&P Summit in Quebec is coming up in just a few weeks, May  6-8. At the moment I'm scheduled to do a talk on Dependency Injection with Scott Densmore and a talk on Open Source with Peter Provost. I was supposed to be at the summit in Redmond last fall, but I ended up injuring my knee and unable to walk (which makes it pretty tough to present, too). Scott's talk on DI in the fall was centered around our work moving ObjectBuilder towards 2.0; I expect our talk this time will be more focused on the final OB2 and Unity bits that just shipped.

April 02, 2008

xUnit.net RC2 Refresh + ASP.NET MVC Preview 2

Scott and Phil has been patiently asking us when we would add support for ASP.NET MVC Preview 2 for xUnit.net. After we released this refresh this morning, we decided to see if we could quickly add support for them.

Turns out it wasn't that painful, and we finished it. To use this:

  • Go to the RC2 Refresh release page
  • Download the file named xunit-build-1235-installer.zip
  • Unzip its contents alongside the RC2 Refresh binaries
  • Run xunit.installer.exe

That's it! In future builds, this new installer will replace the existing xunitext.runner.installer.exe (which we renamed, since the installer isn't just about test runners any more).

Enjoy!