Making Test Context (ie setup/teardown) a declarative part of mockery

Coordinator
Jan 2, 2010 at 5:22 AM
Edited Jan 3, 2010 at 1:07 PM

A suggestion has been raised to encapsulate the process of test context (i.e. setup and teardown) into the mockery object.  The benefit here is having a declarative view of this inside the unit test itself.  I backed it out an earlier attempt in late december where it was implemented as a simple Action delegate on the .Target method.  My feeling at that time was that (1) it was too generic in .Target and (2) I wasn't using it in my own production tests. 

After thinking about this, I propose the following changes to the Mockery object itself.

Add a method called .ContextSetup with two discrete signatures.

ContextSetup( Action setupAction )
ContextSetup( Func<IDisposable> setupAction)
**

** The difference is that mockery would hold onto the IDisposable instance returned from the delegate and .Dispose it on first .Assert call.

Add a method called .ContextTeardown with one signature

ContextTeardown( Action teardownAction )

Demonstrating How The Methods Work

In the .8 version, test fixture setup runs 'ComposeDatabaseContext()' and disposes it on teardown - and this does not appear in the mockery.


string
[] roleList = new [] {"user", "admin"); string[] actualList; InjectedTest.Target<CustomMembershipProvider>() .Arrange( a => a.AddStrictMock<IRoleCollection>() .ExpectOn<IRoleCollection>( e=> Expect.Call( e.FetchRoles() ).Return(roleList)) .Act( tgt => actualList = a.GetRoles() .Assert( Assert.That( actualList, Is.EqualTo( roleList );

In the proposed version, the test becomes...

string[] roleList = new [] {"user", "admin");
string[] actualList;

InjectedTest.Target<CustomMembershipProvider>()
   .ContextSetup( () => return ComposeDatabaseContext())
   .Arrange( a => a.AddStrictMock<IRoleCollection>()
                   .ExpectOn<IRoleCollection>( e=> Expect.Call( e.FetchRoles() ).Return(roleList))
   .Act( tgt => actualList = a.GetRoles() 
   .Assert( Assert.That( actualList, Is.EqualTo( roleList );

 

Or for the more declarative version (which I prefer) ...

string[] roleList = new [] {"user", "admin");
string[] actualList;

InjectedTest.Target<CustomMembershipProvider>( tgt => actualList = a.GetRoles() )
   .ContextSetup( () => return ComposeDatabaseContext())
   .Arrange( a => a.AddStrictMock<IRoleCollection>()
                   .ExpectOn<IRoleCollection>( e=> Expect.Call( e.FetchRoles() ).Return(roleList))
   .Assert( Assert.That( actualList, Is.EqualTo( roleList );

 

Additional Questions:

Should .ContextSetup be named differently for the version that handles the IDisposable instance?  It seems that this would make reading the code cleaner in the long-run.  Thoughts?

 

 

A suggestion has been raised to encapsulate the process of test context (i.e. setup and teardown) into the mockery object.  The benefit here is having a declarative view of this inside the unit test itself.  I backed it out an earlier attempt in late december where it was implemented as a simple Action delegate on the .Target method.  My feeling at that time was that (1) it was too generic in .Target and (2) I wasn't using it in my own production tests. 

After thinking about this, I propose the following changes to the Mockery object itself.

Add a method called .ContextSetup with two discrete signatures.

ContextSetup( Action setupAction )
ContextSetup( Func<IDisposable> setupAction)
**

** The difference is that mockery would hold onto the IDisposable instance returned from the delegate and .Dispose it on first .Assert call.

Add a method called .ContextTeardown with one signature

ContextTeardown( Action teardownAction )

Demonstrating How The Methods Work

In the .8 version, test fixture setup runs 'ComposeDatabaseContext()' and disposes it on teardown - and this does not appear in the mockery.


string
[] roleList = new [] {"user", "admin");
string[] actualList;

InjectedTest.Target<CustomMembershipProvider>()
.Arrange( a => a.AddStrictMock<IRoleCollection>()
.ExpectOn( e=> Expect.Call( e.FetchRoles() ).Return(roleList))
.Act( tgt => actualList = a.GetRoles()
.Assert( Assert.That( actualList, Is.EqualTo( roleList );

In the proposed version, the test becomes...

string[] roleList = new [] {"user", "admin");
string[] actualList;

InjectedTest.Target<CustomMembershipProvider>()
.ContextSetup( () => return ComposeDatabaseContext())
.Arrange( a => a.AddStrictMock<IRoleCollection>()
.ExpectOn( e=> Expect.Call( e.FetchRoles() ).Return(roleList))
.Act( tgt => actualList = a.GetRoles()
.Assert( Assert.That( actualList, Is.EqualTo( roleList );

Or for the more declarative version (which I prefer) ...

string[] roleList = new [] {"user", "admin");
string[] actualList;

InjectedTest.Target<CustomMembershipProvider>( tgt => actualList = a.GetRoles() )
.ContextSetup( () => return ComposeDatabaseContext())
.Arrange( a => a.AddStrictMock<IRoleCollection>()
.ExpectOn( e=> Expect.Call( e.FetchRoles() ).Return(roleList))
.Assert( Assert.That( actualList, Is.EqualTo( roleList );