A single void method that creates a new object

I have a method similar to the following:

public void ExecuteSomeCommand() { new MyCommand( someInt, SomeEnum.EnumValue ).Execute(); } 

I would like to verify that the enum value that is passed to the constructor of the ICommand object that I create is the correct value. Is there a way to do this using Rhino.Mocks?

+8
c # unit-testing mvvm rhino-mocks
source share
2 answers

Option 1: using a seam

The easiest way is to reorganize this method using a seam:

 public void ExecuteSomeCommand() { this.CreateCommand(someInt, SomeEnum.EnumValue).Execute(); } // Your seam protected virtual ICommand CreateCommand(int someInt, SomeEnum someEnum) { return new MyCommand(someInt, SomeEnum.EnumValue); } 

This way you can intercept the creation of the β€œnew” statement by extending this class. When done manually, it might look like this:

 public FakeSomeService : SomeService { public int SomeInt; public SomeEnum SomeEnum; protected override Command CreateCommand(int someInt, SomeEnum someEnum) { this.SomeInt = someInt; this.SomeEnum = someEnum; return new FakeCommand(); } private sealed class FakeCommand : Command { public override void Execute() { } } } 

This fake class can be used in your testing methods.


Option 2: Separate Behavior and Data

The best way is to separate the data from the behavior. The team has both data (message) and behavior (processing this message). If you are allowed to make such a change in the code base: separate it, for example, by defining commands and command handlers. Here is an example:

 // Define an interface for handling commands public interface IHandler<TCommand> { void Handle(TCommand command); } // Define your specific command public class MyCommand { public int SomeInt; public SomeEnum SomeEnum; } // Define your handler for that command public class MyCommandHandler : IHandler<MyCommand> { public void Handle(MyCommand command) { // here your old execute logic } } 

Now you can use dependency injection to inject the handler into the class you want to test. Now this class will look like this:

 public class SomeService { private readonly IHandler<MyCommand> handler; // Inject a handler here using constructor injection. public SomeService(IHandler<MyCommand> handler) { this.handler = handler; } public void ExecuteSomeCommand() { this.handler.Handle(new MyCommand { SomeInt = someInt, SomeEnum = someEnum }); } } 

Since you have now separated the data from the behavior, it will be very easy to create a fake command handler (or create it using Rhino mocks), which checks if the command is sent correctly to the handler. In manual mode, it will look like this:

 public class FakeHandler<TCommand> : IHandler<TCommand> { public TCommand HandledCommand { get; set; } public void Handle(TCommand command) { this.HandledCommand = command; } } 

This fake handler can be reused during the unit testing project. A test using this FakeHandler might look like this:

 [TestMethod] public void SomeTestMethod() { // Arrange int expected = 23; var handler = new FakeHandler<MyCommand>(); var service = new SomeService(handler); // Act service.ExecuteSomeCommand(); // Assert Assert.AreEqual(expected, handler.HandledCommand.SomeInt); } 

Disabling data from behavior not only makes your application more testable. This makes your application more resilient to change. For example, cross-cutting issues can be added to execute commands without the need to make changes to any handler in the system. Since IHandler<T> is a one-method interface, it is very easy to write a decorator that can wrap each handler and add things like a log, audit audit, profiling, validation, transaction processing, fault tolerance, etc. You can learn more about this in this article .

+11
source share

No, of which I know. The closest thing that comes to my mind is to use a factory and then create a StrictMock that factory. Something like that:

 readonly ICommandFactory factory; public Constructor(ICommandFactory factory) { this.factory = factory; } public void ExecuteSomeCommand() { factory.Create( someInt, SomeEnum.EnumValue ).Execute(); } 

then you can put the invokation expectations on Create() .

NTN

+2
source share

All Articles