If you are like me then you have probably ran into a wall with using ASP.NET MVC View Engine to render your awesome Dynamic HTML Email Templates. At least you put up a fight using a lot of fake data. It is actually possible to get around it!
var oldContext = HttpContext.Current;
HttpContext.Current = new HttpContext(HttpContext.Current.Request,
fakeResponse);
var html = new HtmlHelper(new ViewContext(fakeControllerContext,
new FakeView(), fakeViewDataDictionary, new TempDataDictionary()),
new ViewPage());
html.RenderPartial(viewName, viewData, viewDataDictionary);
HttpContext.Current = oldContext; //yay
Though, because you’re reading this you’re like me and you never give up! So how, how do you get around all of this? The answer is Spark. Eeek, another DLL? Yes, Spark is its own View Engine which is an entire different framework. Yes, you have to go to their website download the DLLS, put it in your Lib folder and reference it in your code. Let me tell you now, it is well worth it. Let’s dive in!
Let’s write the code to render our email using the Spark. We want our code to take in the template name, something like: “ForgotUsernameEmail.spark” and we also want it to reuse our current ViewData Object which is of type ViewDataDictionary and contains Person data, we will need to add this into our own implementation of AbstractSparkView. See samples bellow:
Render Email Method:
public string RenderEmail(string sparkViewName, ViewDataDictionary
viewData)
{
var email = new StringWriter();
var view = (EmailTemplateBase) _engine.CreateInstance(new
SparkViewDescriptor().AddTemplate(sparkViewName));
view.ViewData = viewData;
try
{
view.RenderView(email);
}
finally
{
_engine.ReleaseInstance(view);
}
return email.ToString();
}
Oops thanks Arnis, forgot to mention EmailTemplateBase is just an extended version of AbstractSparkView that includes the ASP.NET MVC ViewDataDictionary.
Custom Spark AbstractSparkView with ViewData implementation:
public abstract class EmailTemplateBase : AbstractSparkView
{
public ViewDataDictionary ViewData { get; set; }
public object Eval(string expression)
{
return ViewData.Eval(expression);
}
public string Eval(string expression, string format)
{
return ViewData.Eval(expression, format);
}
}
So that’s done, let’s make the template… In my MVC Web Project I am going to add into my Views folder or maybe even Views/Email
a file called “ForgotUsernameEmail.spark”.
Dear ${#name}:
Your username is ${#userName}.
Thank You.
I also put in a use tag to pull down a Signature file, since this is the same in everyone of my emails. Now let’s actually write the code to call it:
string email = RenderEmail("ForgotUsernameEmail.spark",ViewData);
And that’s all you need to do, well besides read up on spark syntax: http://www.sparkviewengine.com/documentation/configuring
What do you think?
April 21, 2009
If your reading this I assume you are either looking for or have an interest in a mocking framework for testing your .NET Applications.
In this tutorial I will take you through a framework called Moq for (.NET 3.5) released under the New BSD License. However, I will not be discussing what Mocking is for that is outside the scope of this tutorial. What is mocking/mock object?
Before we jump in to code, here are some important links:
Get Moq.
Moq API.
So lets dive in, assuming you already added a reference to the Moq DLL in your project. Let’s start out by creating a new Abstract class to your project. During this session I am going to call this class: UnitBaseAbstractClass for readability.
Creating A Base Test Class
UnitBaseAbstractClass: In charge of setting up Moq environment per TestClass.
1. First let’s add the Moq namespace to our newly created class.
using Moq;
2. Add the [TestClass] attribute to the top of the class, for anything extending this class will need to be a test.
using Moq;
namespace MyUnitTests
{
[TestClass]
public abstract class UnitBaseAbstractClass
{
}
}
3. We are now going to add two public members to UnitBaseAbstractClass these are of type MockFactory and AutoMockContainer.
MockFactory: A utility factory used to manage a mocks lifecycle.
AutoMockContainer: A container used to automatically inject mocks into desired objects.
using Moq;
namespace MyUnitTests
{
[TestClass]
public abstract class UnitBaseAbstractClass
{
public MockFactory _factory;
public AutoMockContainer _container;
}
}
4. To setup our Moq base class we will create a method called Setup which will take in a MockBehavior. In this tutorial we will only go into using, MockBehavior.Default.
MockBehavior: Tells the MockFactory how to behave. Strict behavior throws an exception whenever a mock isn’t setup
exactly as its mocked object. Loose will never throw an exception and Default is setup to use Loose.
(If you don’t understand what this means it’s alright to move on, as it will not affect you yet.)
5. After creating Setup we are going to instantiate both MockFactory and and AutoMockContainer the factory will need the behavior passed into Setup and the automock will need the factory.
using Moq;
namespace MyUnitTests
{
[TestClass]
public abstract class UnitBaseAbstractClass
{
public MockFactory _factory;
public AutoMockContainer _container;
public void Setup(MockBehavior behavior)
{
_factory = new MockFactory(behavior);
_container = new AutoMockContainer(_factory);
}
}
}
6. Last but not least we want to implement our [TestCleanup]. We will call this method VerifyAll, all it will do is verify that all our mocks were used and that they were used correctly. Making the final code look something like this:
using Moq;
namespace MyUnitTests
{
[TestClass]
public abstract class UnitBaseAbstractClass
{
public MockFactory _factory;
public AutoMockContainer _container;
public void Setup(MockBehavior behavior)
{
_factory = new MockFactory(behavior);
_container = new AutoMockContainer(_factory);
}
[TestCleanup]
public void VerifyAll()
{
_factory.VerifyAll();
}
}
}
A Test Class using our Base Class
1. Let’s start by writing some tests against this pseudo PersonService class:
namespace MyRear
{
public class PersonService
{
private readonly ISaveStuff _saveStuff;
public bool SavePerson(Person person)
{
try{
return _saveStuff.Save(person);
}
catch (Exception ex){
throw new CustomException(ex);
}
}
}
}
2. Create our test class using the base class. Our[TestInitialize] will be using the base Setup method and we will use the AutoMockContainer to create a new instance of typePersonService. We will also create a new person.
namespace MyRearTests
{
[TestClass]
public class PersonServiceTests
{
private readonly PersonService _service;
private Person _person;
[TestInitialize]
public void Setup()
{
Setup(MockBehavior.Default);
_service = _container.Create<PersonService>();
_person = new Person();
}
}
}
2.5. Ok, it is time now to write our tests! However, before this I want to show you how to mock up _saveStuff.Save because this code calls Database Code, which we do not want to access in our testing envoirnment!
return _saveStuff.Save(person);
3. First we want to get a mock object for ISaveStuff because this is how we are going to call Save. We do this with this line of code:
_container.GetMock<ISaveStuff>()
4. We then want to make sure that we mock Save and are able to put in our own person object. We expand by using some simple Linq within the Expect method:
_container.GetMock<ISaveStuff>()
.Expect(s => s.Save(_person))
5. We then need to tell the object what to return (in this case a bool of value true) and after it returns make sure to verify that this mock was implemented correctly.
_container.GetMock<ISaveStuff>()
.Expect(s => s.Save(_person))
.Returns(true)
.Verifiable();
6. Lets make it a test now!
namespace MyRearTests
{
[TestClass]
public class PersonServiceTests
{
private readonly PersonService _service;
private Person _person;
[TestInitialize]
public void Setup()
{
Setup(MockBehavior.Default);
_service = _container.Create<PersonService>();
_person = new Person();
}
[TestMethod]
public void SavePersonSuccess()
{
var result =
_container.GetMock<ISaveStuff>()
.Expect(s => s.Save(_person))
.Returns(true)
.Verifiable();
Assert.IsTrue(result, "Person should save.");
}
}
}
6.5. Lets add another test for returning false, a failed save.
namespace MyRearTests
{
[TestClass]
public class PersonServiceTests
{
private readonly PersonService _service;
private Person _person;
[TestInitialize]
public void Setup()
{
Setup(MockBehavior.Default);
_service = _container.Create<PersonService>();
_person = new Person();
}
[TestMethod]
public void SavePersonSuccess()
{
var result =
_container.GetMock<ISaveStuff>()
.Expect(s => s.Save(_person))
.Returns(true)
.Verifiable();
Assert.IsTrue(result, "Person should save.");
}
[TestMethod]
public void SavePersonFail()
{
var result =
_container.GetMock<ISaveStuff>()
.Expect(s => s.Save(_person))
.Returns(true)
.Verifiable();
Assert.IsFalse(result, "Person should not save.");
}
}
}
7. The last test is a bit tricky and it is also the reason why we caught the base exception and threw our own custom exception. First lets jump back to:
_container.GetMock<ISaveStuff>()
.Expect(s => s.Save(_person))
8. Handling exceptions is different then normal asserts throwing them is different too. In order to throw an exception we need to call the Throws method instead of returns.
_container.GetMock<ISaveStuff>()
.Expect(s => s.Save(_person))
.Throws(new Exception("Save Threw Up"))
.Verifiable();
9. Now lets make sure we handle the code. We do this with the [ExpectedException] attribute on our test methods.
[TestMethod]
[ExpectedException(typeof(CustomException))]
public void SavePersonException()
{
_container.GetMock<ISaveStuff>()
.Expect(s => s.Save(_person))
.Throws(new Exception("Save Threw Up"))
.Verifiable();
}
10. The Final Test looks like this:
namespace MyRearTests
{
[TestClass]
public class PersonServiceTests
{
private readonly PersonService _service;
private Person _person;
[TestInitialize]
public void Setup()
{
Setup(MockBehavior.Default);
_service = _container.Create<PersonService>();
_person = new Person();
}
[TestMethod]
public void SavePersonSuccess()
{
var result =
_container.GetMock<ISaveStuff>()
.Expect(s => s.Save(_person))
.Returns(true)
.Verifiable();
Assert.IsTrue(result, "Person should save.");
}
[TestMethod]
public void SavePersonFail()
{
var result =
_container.GetMock<ISaveStuff>()
.Expect(s => s.Save(_person))
.Returns(true)
.Verifiable();
Assert.IsFalse(result, "Person should not save.");
}
[TestMethod]
[ExpectedException(typeof(CustomException))]
public void SavePersonException()
{
_container.GetMock<ISaveStuff>()
.Expect(s => s.Save(_person))
.Throws(new Exception("Save Threw Up"))
.Verifiable();
}
}
}
I hope this helped you out a bit more in understand Moq. Good Luck!
What do you think?