二、 创建新的单元测试
因为我正在遵循测试驱动开发思想构建本文中的论坛应用程序,所以我总是先从创建一组新的单元测试开始。列表1显示了这一组新的单元测试。
列表1—Controllers\ForumControllerTest.cs
using System.Collections.Generic;
using System.Web.Mvc;
using LinqToSqlExtensions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Web.Mvc;
using MvcFakes;
using MvcForums.Controllers;
using MvcForums.Models;
namespace MvcForums.Tests.Controllers
{
[TestClass]
public class ForumControllerTest
{
private IForumRepository _repository;
[TestInitialize]
public void Initialize()
{
//创建模拟数据
var dataContext = new FakeDataContext();
dataContext.Insert(new Message(1, null, null, "Robert", "Welcome to the MVC forums!", "body1"));
dataContext.Insert(new Message(2, 1, 1, "Stephen", "RE:Welcome to the MVC forums!", "body2"));
dataContext.Insert(new Message(3, 1, 2, "Robert", "RE:Welcome to the MVC forums!", "body3"));
dataContext.Insert(new Message(4, null, null, "Mark", "Another message", "body4"));
dataContext.Insert(new Message(5, 4, 4, "Stephen", "Yet another message", "body5"));
dataContext.Insert(new Message(6, 4, 5, "Jane", "Yet another message", "body6"));
//返回repository
_repository = new ForumRepository(dataContext);
}
[TestMethod]
public void IndexReturnsMessageThreads()
{
// Arrange
var controller = new ForumController(_repository);
// Act
var result = controller.Index() as ViewResult;
// Assert
var model = result.ViewData.Model as List<Message>;
Assert.AreEqual(2, model.Count);
}
/// <summary>
///验证Thread(1)动作将返回3条消息,而且所有的消息都有一个
///值为1的Id或者ParentThreadId属性
/// </summary>
[TestMethod]
public void ThreadReturnsMessagesInThread()
{
// Arrange
var controller = new ForumController(_repository);
// Act
var result = controller.Thread(1) as ViewResult;
// Assert
var model = result.ViewData.Model as List<Message>;
Assert.AreEqual(3, model.Count); //第一个线程中的3条消息
foreach (var m in model)
{
Assert.IsTrue(m.Id == 1 || m.ParentThreadId == 1);
}
}
[TestMethod]
public void NewThreadIncrementsThreadCount()
{
// Arrange
var controller = new ForumController(_repository);
var originalThreadCount = _repository.SelectThreads().Count;
// Act
var form = new FormCollection();
form.Add("author", "Stephen");
form.Add("subject", "New Thread!");
form.Add("body", "Body of new thread");
var result = controller.Create(form);
// Assert
var newThreadCount = _repository.SelectThreads().Count;
Assert.AreEqual(originalThreadCount + 1, newThreadCount);
}
[TestMethod]
public void NewReplyIncrementsMessageCount()
{
// Arrange
var controller = new ForumController(_repository);
var originalMessageCount = _repository.SelectMessages(1).Count;
// Act
var form = new FormCollection();
form.Add("parentThreadId", "1");
form.Add("parentMessageId", "1");
form.Add("author", "Stephen");
form.Add("subject", "New Thread!");
form.Add("body", "Body of new thread");
var result = controller.Create(form);
// Assert
var newMessageCount = _repository.SelectMessages(1).Count;
Assert.AreEqual(originalMessageCount + 1, newMessageCount);
}
[TestMethod]
public void NewReplyDoesNotIncrementsThreadCount()
{
// Arrange
var controller = new ForumController(_repository);
var originalThreadCount = _repository.SelectThreads().Count;
// Act
var form = new FormCollection();
form.Add("parentThreadId", "1");
form.Add("parentMessageId", "1");
form.Add("author", "Stephen");
form.Add("subject", "New Thread!");
form.Add("body", "Body of new thread");
var result = controller.Create(form);
// Assert
var newThreadCount = _repository.SelectThreads().Count;
Assert.AreEqual(originalThreadCount, newThreadCount);
}
}
}
using System.Web.Mvc;
using LinqToSqlExtensions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Web.Mvc;
using MvcFakes;
using MvcForums.Controllers;
using MvcForums.Models;
namespace MvcForums.Tests.Controllers
{
[TestClass]
public class ForumControllerTest
{
private IForumRepository _repository;
[TestInitialize]
public void Initialize()
{
//创建模拟数据
var dataContext = new FakeDataContext();
dataContext.Insert(new Message(1, null, null, "Robert", "Welcome to the MVC forums!", "body1"));
dataContext.Insert(new Message(2, 1, 1, "Stephen", "RE:Welcome to the MVC forums!", "body2"));
dataContext.Insert(new Message(3, 1, 2, "Robert", "RE:Welcome to the MVC forums!", "body3"));
dataContext.Insert(new Message(4, null, null, "Mark", "Another message", "body4"));
dataContext.Insert(new Message(5, 4, 4, "Stephen", "Yet another message", "body5"));
dataContext.Insert(new Message(6, 4, 5, "Jane", "Yet another message", "body6"));
//返回repository
_repository = new ForumRepository(dataContext);
}
[TestMethod]
public void IndexReturnsMessageThreads()
{
// Arrange
var controller = new ForumController(_repository);
// Act
var result = controller.Index() as ViewResult;
// Assert
var model = result.ViewData.Model as List<Message>;
Assert.AreEqual(2, model.Count);
}
/// <summary>
///验证Thread(1)动作将返回3条消息,而且所有的消息都有一个
///值为1的Id或者ParentThreadId属性
/// </summary>
[TestMethod]
public void ThreadReturnsMessagesInThread()
{
// Arrange
var controller = new ForumController(_repository);
// Act
var result = controller.Thread(1) as ViewResult;
// Assert
var model = result.ViewData.Model as List<Message>;
Assert.AreEqual(3, model.Count); //第一个线程中的3条消息
foreach (var m in model)
{
Assert.IsTrue(m.Id == 1 || m.ParentThreadId == 1);
}
}
[TestMethod]
public void NewThreadIncrementsThreadCount()
{
// Arrange
var controller = new ForumController(_repository);
var originalThreadCount = _repository.SelectThreads().Count;
// Act
var form = new FormCollection();
form.Add("author", "Stephen");
form.Add("subject", "New Thread!");
form.Add("body", "Body of new thread");
var result = controller.Create(form);
// Assert
var newThreadCount = _repository.SelectThreads().Count;
Assert.AreEqual(originalThreadCount + 1, newThreadCount);
}
[TestMethod]
public void NewReplyIncrementsMessageCount()
{
// Arrange
var controller = new ForumController(_repository);
var originalMessageCount = _repository.SelectMessages(1).Count;
// Act
var form = new FormCollection();
form.Add("parentThreadId", "1");
form.Add("parentMessageId", "1");
form.Add("author", "Stephen");
form.Add("subject", "New Thread!");
form.Add("body", "Body of new thread");
var result = controller.Create(form);
// Assert
var newMessageCount = _repository.SelectMessages(1).Count;
Assert.AreEqual(originalMessageCount + 1, newMessageCount);
}
[TestMethod]
public void NewReplyDoesNotIncrementsThreadCount()
{
// Arrange
var controller = new ForumController(_repository);
var originalThreadCount = _repository.SelectThreads().Count;
// Act
var form = new FormCollection();
form.Add("parentThreadId", "1");
form.Add("parentMessageId", "1");
form.Add("author", "Stephen");
form.Add("subject", "New Thread!");
form.Add("body", "Body of new thread");
var result = controller.Create(form);
// Assert
var newThreadCount = _repository.SelectThreads().Count;
Assert.AreEqual(originalThreadCount, newThreadCount);
}
}
}
列表1中的测试类包含下列单元测试:
? IndexReturnsMessageThreads()—验证Index()动作将返回2条ParentThreadId属性为NULL的消息;
? ThreadReturnsMessagesInThread()—验证Thread()动作将返回一个指定线程中的所有消息;
? NewThreadIncrementsThreadCount()—验证发送一条新的没有提供ParentThreadId属性的消息将使消息线程数加1;
? NewReplyIncrementsMessageCount()—验证把一条应答消息发送到一个线程将使该线程中的消息数加1;
? NewReplyDoesNotIncrementThreadCount()—验证发送一条应答消息不会增加总线程的数目。
上面这些单元测试应该是非常易于理解的。它们都利用了虚构的DataContext类。通过这种方式,数据库本身是不会被实际上使用或修改的。
此外还请注意,这些单元测试本身并不会与DataContext类直接交互。而是,这些单元测试仅仅与ForumRepository类交互。通过这种方式,如果我们决定改变我们的数据访问技术—例如,我们把LINQ to SQL改变为NHibernate—那么,我们不需要改变我们的单元测试。如果我们改变数据访问技术,那么,我们仅仅需要改变Initialize()方法。