我想單元測試一個採用FormCollection
並具有Find
方法的控制器。我已成功實施假冒DbContext
和FakeDbSet
(從here),以便我可以在我的測試中使用假物件。在FakeDbSet實現中僞造find方法
我想測試的具體方法是這樣的:
//
// POST: /Order/SettleOrders
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SettleOrders(FormCollection c)
{
int i = 0;
if (ModelState.IsValid)
{
var ordersCollection = new List<Order>();
// Get values of form
var OrderIdArray = c.GetValues("item.OrderId");
var UnitPriceArray = c.GetValues("item.UnitPrice");
for (i = 0; i < OrderIdArray.Count(); i++)
{
// Find order in database and update the unitprice and isconfirmed status
Order order = db.Orders.Find(Convert.ToInt32(OrderIdArray[i]));
order.UnitPrice = Convert.ToDecimal(UnitPriceArray[i]);
order.IsConfirmed = true;
db.SetModified(order);
ordersCollection.Add(order);
}
db.SaveChanges();
}
// Return orders of this date to view
var currentDate = DateTime.Today;
var orders = db.Orders.Include(o => o.Product)
.Include(o => o.User)
.Where(o => o.Date == currentDate);
return View("Confirmation", orders.ToList().OrderBy(o => o.User.Name));
}
這是我建立我的OrderController
的測試使用Moq
:
[TestInitialize]
public void OrderControllerTestInitialize()
{
// Arrange
var unconfirmedMemoryItems = new FakeOrderSet
{
// @TODO Tests/methods should ideally not be dependent on DateTime.Today...
new Order { OrderId = 1, UnitPrice = 1.00M, Quantity = 2, Date = DateTime.Today, IsConfirmed = false },
new Order { OrderId = 2, UnitPrice = 2.00M, Quantity = 1, Date = DateTime.Today, IsConfirmed = false }
};
// Create mock unit of work
var unconfirmedMockData = new Mock<ISeashellBrawlContext>();
unconfirmedMockData.Setup(m => m.Orders).Returns(confirmedMemoryItems);
// Setup controller
unconfirmedOrderController = new OrderController(confirmedMockData.Object);
}
然後測試去喜歡這確認未經確認的訂單正在確認。
[TestMethod]
public void TestSettleOrdersPost()
{
// Invoke
FormCollection form = CreatesettleOrdersPostFormCollection();
var viewResult = unconfirmedOrderController.SettleOrders(form) as ViewResult;
var ordersFromView = (IEnumerable<Order>)viewResult.Model;
// Assert
Assert.AreEqual(3, ordersFromView.ElementAt(0).Quantity,
"New item should be added to older one since it has same index and is of same date");
Assert.AreEqual(true, ordersFromView.ElementAt(0).IsConfirmed,
"The item should also be set to confirmed");
}
// Helper methods
private static FormCollection CreatesettleOrdersPostFormCollection()
{
FormCollection form = new FormCollection();
form.Add("item.OrderId", "1");
form.Add("item.UnitPrice", "2.00");
form.Add("item.OrderId", "2");
form.Add("item.UnitPrice", "3.00");
return form;
}
不幸的是我得到了以下錯誤消息:
測試名稱:TestSettleOrdersPost 結果消息:
System.NullReferenceException:未設置爲一個對象的實例 對象引用。結果堆棧跟蹤:在 Controllers.OrderController.SettleOrders(的FormCollection三) 控制器\ OrderController.cs:行121
這可能與假Find
方法沒有做它應該做的事。我使用的查找方法如下所示:
class FakeOrderSet : FakeDbSet<Order>
{
public override Order Find(params object[] keyValues)
{
var id = Convert.ToInt32(keyValues[0]);
Order o = null;
IQueryable<Order> keyQuery = this.AsQueryable<Order>();
foreach (var order in keyQuery)
{
if (order.OrderId == id)
{
o = order;
}
}
return o;
}
}
我不知道如何改進此代碼。看着它,我確信它應該起作用。因爲我是單元測試的7天noobot,但這個信念並沒有多大價值。我希望有人能幫助我。
_「這可能需要做......」在121行之前放置一個斷點,看看會發生什麼。 – CodeCaster
@CodeCaster我在做單元測試時如何在代碼中放置斷點?我無法做到這一點,我也不能寫信給控制檯......讓這些工具可用將是一個巨大的幫助。我找到了一個答案:'Debug' - >'在當前上下文中測試'(或其他) –
請參閱http:// stackoverflow。com/questions/12594018/can-debug-a-unit-testing-project-in-visual-studio-2012 and http://stackoverflow.com/questions/4103712/stepping-through-and-debugging-code-in-單元測試。在測試資源管理器中右鍵單擊該測試,如果其他方式不起作用,請單擊「調試」。 – CodeCaster