在我們的基於Music Store Tutorial的Entity Framework 4.0的MVC4應用程序中,我們使用Moq來模擬DbContext
,單元測試是邏輯。我們的一種方法很難測試,因爲它使用了HttpContext
或HttpContextBase
。一個示例方法是這樣的:如何在ShoppingCart控制器/模型中模擬HttpContext
public static ShoppingCart GetCart(HttpContextBase context)
{
var cart = new ShoppingCart();
cart.ShoppingCartId = cart.GetCartId(context);
return cart;
}
從HttpContextBase
收集的唯一屬性是[CartSessionKey]
因爲可以在這裏看到:
public string GetCartId(HttpContextBase context)
{
if (context.Session[CartSessionKey] == null)
{
if (!string.IsNullOrWhiteSpace(context.User.Identity.Name))
{
context.Session[CartSessionKey] =
context.User.Identity.Name;
}
else
{
// Generate a new random GUID using System.Guid class
Guid tempCartId = Guid.NewGuid();
// Send tempCartId back to client as a cookie
context.Session[CartSessionKey] = tempCartId.ToString();
}
}
return context.Session[CartSessionKey].ToString();
}
我們聽說的恐怖故事HttpContext
是一個非常複雜的類和如果你打印它,你有足夠的紙張八次環繞地球。
不過我們想嘲笑它。問題是如何。我們想要模擬的屬性是[CartSessionKey]
,以及來自上下文的屬性爲contest.User.Identity.Name
。
我們懷疑,我們需要使用這樣的事情:
var mockData = new Mock<FakeContext>();
mockData.Setup(m => m.Orders).Returns(memoryOrderItems);
mockData.Setup(m => m.Carts).Returns(memoryCartItems);
Mock<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
Mock<HttpRequestBase> mockHttpRequest = new Mock<HttpRequestBase>();
mockHttpRequest.Setup(x => x.CartSessionKey).Returns(1);
mockHttpContext.Setup(x => x.Request).Returns(mockHttpRequest.Object);
,但我們無法找到如何具體實現這個,所以我們沒有得到在使用context.Session[CartSessionKey]
或context.User.Identity.Name
方法的任何錯誤。
我們希望有人能幫助我們。
/編輯
當我們這樣做:
var memoryUserItems = new FakeDbSet<User>()
{
new User { Email = "[email protected]",
FullName = "Test Person",
isAvailable = true,
Name = "WHat"
},
new User { Email = "[email protected]",
FullName = "Test Person 2",
isAvailable = true,
Name = "WHat 2"
}
};
(...) Other memory...Items
然後將此:
// Create mock units of work
var mockData = new Mock<FakeContext>();
mockData.Setup(m => m.Orders).Returns(memoryOrderItems);
mockData.Setup(m => m.Carts).Returns(memoryCartItems);
mockData.Setup(m => m.Users).Returns(memoryUserItems);
var principalMock = new Mock<IPrincipal>();
var identityMock = new Mock<IIdentity>();
var userMock =
identityMock.Setup(x => x.Name).Returns("Test!");
identityMock.Setup(x => x.IsAuthenticated).Returns(true); // optional ;)
mockData.Setup(x => x.Identity).Returns(identityMock.Object);
var httpReqBase = new Mock<HttpRequestBase>(); // this is useful if you want to test Ajax request checks or cookies in the controller.
var httpContextBase = new Mock<HttpContextBase>();
httpContextBase.Setup(x => x.User).Returns(principalMock.Object);
httpContextBase.Setup(x => x.Session[It.IsAny<string>()]).Returns(1); //Here is the session indexer. You can swap 'any' string for specific string.
httpContextBase.Setup(x => x.Request).Returns(httpReqBase.Object);
我們得到的錯誤是:
錯誤3「項目。 Models.FakeContext'確實不是 包含「身份」和沒有擴展方法 「身份」接受 類型「project.Models.FakeContext」的第一個參數的定義可以發現 (是否缺少使用指令或程序集 引用?)
/edit2
爲了更清楚。我測試的實際方法如下:
public ActionResult Complete(int id)
{
// Make sure that user is currentuser and otherwise bring user to our Thief page
if (id != db.GetCurrentUserId())
{
return View("Thief");
}
var cart = ShoppingCart.GetCart(this.HttpContext);
var currentDate = DateTime.Today;
var viewModel = new ShoppingCartViewModel
{
CartItems = cart.GetCartItems(),
CartTotal = cart.GetTotal(),
ProductItems = db.Products.ToList()
};
if (viewModel.CartItems.Count() == 0)
{
return View("Empty");
}
// Try to write cart to order table
try
{
foreach (var item in viewModel.CartItems)
{
ProcessOrder(item, id, currentDate);
}
// after this we empty the shopping cart
cart.EmptyCart();
return View();
}
catch
{
// Invalid - display error page
return View("Error");
}
}
可以看出該var cart = ShoppingCart.GetCart(this.HttpContext);
使用this.HttpContext
。在測試中,我只是做controller.Complete(1)
。我猜想我無法將新的HttpContext
傳遞給控制器?
/編輯3
雖然使用下面的代碼與嘲笑我得到以下信息:
Test Name: TestCheckoutCompleteShouldWithEmptyCart
Test FullName: Controllers.CheckoutControllerTest.TestCheckoutCompleteShouldWithEmptyCart
Test Source: Controllers\CheckoutControllerTest.cs : line 141
Test Outcome: Failed
Test Duration: 0:00:00.0158591
Result Message:
Test method Controllers.CheckoutControllerTest.TestCheckoutCompleteShouldWithEmptyCart threw exception:
System.NullReferenceException: Object reference not set to an instance of an object.
Result StackTrace:
at Models\ShoppingCart.cs:line 170
at \Models\ShoppingCart.cs:line 20
at \Controllers\CheckoutController.cs:line 48
at Controllers\CheckoutControllerTest.cs:line 143
您是否正在測試公共字符串GetCartId(HttpContextBase上下文)方法?你的MUT是什麼? GetCart或GetCartId? – Spock
Hi @Spock Hi,什麼是MUT? 'GetCartId'是GetCart依賴的主要關注點。 –
對不起,這是測試方法。你試圖達到的目標非常簡單。看到我的答案,還有其他幾種做法。樂於幫助 – Spock