我只是用mvc 4来研究tdd。
我有一个orderscontroller,它在构造函数中带有一个工作单元接口:
public OrdersController(IUnitOfWork db)
{
this.db = db;
}
//
// GET: /Orders/
public ActionResult Index()
{
return View(db.Orders.GetAll());
}
我对这个索引()进行了几次测试。
[TestClass]
public class when_the_order_controller_index_action_executes
{
[TestMethod]
public void it_should_render_the_default_view()
{
var uow = new Mock<IUnitOfWork>();
var db = uow.Object;
var orders = new List<Order>()
{
new Order{CreatedDate = DateTime.Now.AddMonths( -3),OrderID = Guid.NewGuid()},
new Order{CreatedDate = DateTime.Now,OrderID = Guid.NewGuid()}
};
uow.Setup(r => r.Orders.GetAll())
.Returns(orders);
//arrange
var controller = new OrdersController(db);
//act
var result = controller.Index() as ViewResult;
//assert
Assert.AreEqual("", result.ViewName);
}
[TestMethod]
public void it_should_pass_orders_as_the_model()
{
var uow = new Mock<IUnitOfWork>();
var db = uow.Object;
var orders = new List<Order>()
{
new Order{CreatedDate = DateTime.Now.AddMonths( -3),OrderID = Guid.NewGuid()},
new Order{CreatedDate = DateTime.Now,OrderID = Guid.NewGuid()}
};
uow.Setup(r => r.Orders.GetAll())
.Returns(orders);
//arrange
var controller = new OrdersController(db);
//act
var model = ((ViewResult)controller.Index()).ViewData.Model as IEnumerable<Order>;
//assert
Assert.IsTrue(orders.Equals(model));
}
}
您会注意到两个测试中有很多代码重复,用于创建GetAll可以返回的列表......
说一个可重用的函数来返回两个测试都可以调用的列表是好/坏的做法吗?
我所写的测试的任何一般性建议也会受到赞赏,因为我现在只接受tdd的爱!
答案 0 :(得分:3)
是的,通常认为在单元测试的[TestInitialize]
阶段重构所有公共代码初始化是一种好习惯。您还可以将单元测试的所有常见初始化/断言部分外部化为您可重复使用的方法。
所以在你的特定例子中:
[TestClass]
public class when_the_order_controller_index_action_executes
{
private IUnitOfWork db;
private OrdersController sut;
[TestInitialize]
public void TestInitialize()
{
var uow = new Mock<IUnitOfWork>();
this.db = uow.Object;
var orders = new List<Order>()
{
new Order{ CreatedDate = DateTime.Now.AddMonths(-3),OrderID = Guid.NewGuid() },
new Order{ CreatedDate = DateTime.Now,OrderID = Guid.NewGuid() }
};
uow.Setup(r => r.Orders.GetAll()).Returns(orders);
this.sut = new OrdersController(db);
}
[TestMethod]
public void it_should_render_the_default_view()
{
//act
var result = this.sut.Index() as ViewResult;
//assert
Assert.AreEqual("", result.ViewName);
}
[TestMethod]
public void it_should_pass_orders_as_the_model()
{
//act
var model = ((ViewResult)this.sut.Index()).ViewData.Model as IEnumerable<Order>;
//assert
Assert.IsTrue(orders.Equals(model));
}
}
但通常uow.Setup(r => r.Orders.GetAll()).Returns(orders);
是每个单元测试的//arrange
阶段的一部分,因为它不同。这是你定义期望的地方。在您的特定示例中,我还将两个测试合并为一个:
[TestClass]
public class when_the_order_controller_index_action_executes
{
private IUnitOfWork db;
private OrdersController sut;
[TestInitialize]
public void TestInitialize()
{
var uow = new Mock<IUnitOfWork>();
this.db = uow.Object;
var orders = new List<Order>()
{
new Order{ CreatedDate = DateTime.Now.AddMonths(-3),OrderID = Guid.NewGuid() },
new Order{ CreatedDate = DateTime.Now,OrderID = Guid.NewGuid() }
};
uow.Setup(r => r.Orders.GetAll()).Returns(orders);
this.sut = new OrdersController(db);
}
[TestMethod]
public void it_should_render_the_default_view_and_pass_the_expected_view_model_to_it()
{
//act
var actual = this.sut.Index();
//assert
Assert.IsInstanceOfType(actual, typeof(ViewModel));
var viewResult = (ViewResult)actual;
Assert.AreEqual(model, viewResult.Model);
}
}