No, this question has no roosting construction workers.
I'm not sure if what I'm doing is a good use of the builder pattern or whether its a bastardization of what its intended purpose was. I'm trying to set up mocks in my tests and find myself repeating myself often to set up the mocks, so I've tried to simplify it using a builder to make my mocks for me. I'm not sure if what I have here is a good pattern for this or whether there's a better one.
I have set up a builder to make my API controller for me with mock objects parsed in. I'm using those builder methods to call methods on contained builders that it is using to make the relevant mocks for the controller its building. So there are nested builders within this controller builder that I'm just setting up through the controller's builder methods. Here is my outer ControllerBuilder:
public class DoStuffControllerBuilder
{
private Mock<IRepository> _mockRepo;
private MockStuffLoggerBuilder _loggerBuilder;
private MockAzureQueueManagerBuilder _queueManagerBuilder;
private DoStuffControllerBuilder()
{
_mockRepo = new Mock<IRepository>();
_loggerBuilder = MockStuffLoggerBuilder.GetBuilder();
_queueManagerBuilder = MockAzureQueueManagerBuilder.PrepareBuilder();
}
public bool WasEnqueueCalledOnQueueManager { get { return _queueManagerBuilder.WasSomethingQueued; } }
public Message LastQueuedMessage { get { return _queueManagerBuilder.LastQueuedMessage; } }
public bool CreateJobLogWasCalled { get { return _loggerBuilder.CreateJobLogWasCalled; } }
public int CreateJobLogID { get { return _loggerBuilder.CreateJobLogID; } }
public static DoStuffControllerBuilder GetBuilder()
{
return new DoStuffControllerBuilder();
}
public DoStuffController Build()
{
return new DoStuffController(_mockRepo.Object, _loggerBuilder.BuildMock(), _queueManagerBuilder.BuildMock());
}
public DoStuffControllerBuilder WithRememberEnqueueWasCalled()
{
_queueManagerBuilder.WithRememberSomethingWasQueued();
return this;
}
public DoStuffControllerBuilder WithRememberLastQueuedMessage()
{
_queueManagerBuilder.WithRememberLastQueuedMessage();
return this;
}
public DoStuffControllerBuilder WithRememberCreateLogWasCalled()
{
_loggerBuilder.WithRememberCreateLogWasCalled();
return this;
}
public DoStuffControllerBuilder WithRememberCreateLogID()
{
_loggerBuilder.WithRememberCreateLogID();
return this;
}
}
The code for my inner Azure queue builder is below. Here, I'm using it to set up a mock object to verify something was called later on and remember values. More functionality may be added later.
public class MockAzureQueueManagerBuilder
{
private Mock<IAzureQueueManager> _mockManager;
private bool _rememberWasQueued, _rememberLastMessage;
private Message _lastQueuedMessage;
private bool _wasSomethingQueued;
private MockAzureQueueManagerBuilder()
{
_mockManager = new Mock<IAzureQueueManager>();
}
public bool WasSomethingQueued { get { return _wasSomethingQueued; } }
public Message LastQueuedMessage { get { return _lastQueuedMessage; } }
public static MockAzureQueueManagerBuilder PrepareBuilder()
{
return new MockAzureQueueManagerBuilder();
}
public IAzureQueueManager BuildMock()
{
var setup = _mockManager.Setup(q => q.EnqueueMessageByJobs(It.IsAny<Message>()));
if (_rememberWasQueued || _rememberLastMessage)
setup.Callback<Message>(message =>
{
if (_rememberLastMessage)
_lastQueuedMessage = message;
if (_rememberWasQueued)
_wasSomethingQueued = true;
});
return _mockManager.Object;
}
public MockAzureQueueManagerBuilder WithRememberSomethingWasQueued()
{
_rememberWasQueued = true;
return this;
}
public MockAzureQueueManagerBuilder WithRememberLastQueuedMessage()
{
_rememberLastMessage = true;
return this;
}
}
Finally, here it is in action:
public void AddStuffShouldEnqueueAMessageWithJobs()
{
// given an ID of 1
var builder = DoStuffControllerBuilder.GetBuilder();
var controller = builder.WithRememberEnqueueWasCalled().WithRememberLastQueuedMessage().Build();
var options = new Options {Entities = new List<int> {1}};
// when we post that entity to the controller
controller.Post(options);
// then it calls EnqueueMessageByJobs
Assert.IsTrue(builder.WasEnqueueCalledOnQueueManager, "No message was queued");
// and the ID is the given ID
var lastMessage = builder.LastQueuedMessage;
Assert.AreEqual(1, lastMessage.ID, "The ID on the message is not what was expected");
// and it has at least 1 job
Assert.IsTrue(lastMessage.JobsToDo.Any(), "The message has been queued with no jobs to do");
}
Any tips to get me building nicer much appreciated.