C# 如何在实体框架4.0的MVC4中使用ViewModel模拟方法
我想测试以下方法:C# 如何在实体框架4.0的MVC4中使用ViewModel模拟方法,c#,entity-framework,unit-testing,asp.net-mvc-4,C#,Entity Framework,Unit Testing,Asp.net Mvc 4,我想测试以下方法: public ActionResult Index() { var transactions = db.Transactions.Include(t => t.User) .GroupBy(t => t.UserId) .Select(group => new TransactionViewModel
public ActionResult Index()
{
var transactions = db.Transactions.Include(t => t.User)
.GroupBy(t => t.UserId)
.Select(group => new TransactionViewModel
{
User = group.FirstOrDefault().User.FullName,
UserId = group.FirstOrDefault().UserId,
Total = (group.Sum(t => t.TransactionAmount))
});
// Show lowest balance first
return View(transactions.ToList());
}
此处,交易
模型有一个订单列表
,有一个指向用户
的外键和一些其他属性,请参见:
public class Transaction
{
public int TransactionId { get; set; }
public DateTime Date { get; set; }
public int UserId { get; set; }
public List<Order> Orders { get; set; }
public decimal TransactionAmount { get; set; }
public virtual User User { get; set; }
}
和用于计算属于用户的不同事务的总数
要测试此方法,我有一个FakeDbSet
,并在以下设置中使用一个FakeContext
(这两个都可以在其他控制器的测试中使用):
[TestClass]
public class TransactionControllerTest
{
TransactionController trController;
[TestInitialize]
public void TransactionControllerTestInitialize()
{
// Arrange
var memoryTransactionItems = new FakeDbSet<Transaction>
{
new Transaction {
Date = DateTime.Today,
TransactionAmount = 5.10M,
UserId = 1,
Orders = new List<Order>{
// Categorie 2 and confirmed
new Order { OrderId = 2,
UnitPrice = 2.00M,
Quantity = 1,
Date = DateTime.Today,
IsConfirmed = true,
User = new User {
Name = "Kees",
FullName="Kees Piet",
Email = "Kees@DeHond.nl",
isAvailable = true,
UserId = 1
},
Product = new Product {
Category = new Category {
CategoryId = 2,
Name = "Categorie2"
},
Name = "Testproduct2",
Price = 2.00M,
Visible = true
}
},
// Categorie 2 and confirmed
new Order { OrderId = 2,
UnitPrice = 1.00M,
Quantity = 1,
Date = DateTime.Today,
IsConfirmed = true,
User = new User {
Name = "Jan",
FullName="Jan Piet",
Email = "Jan@DeBouvrier.de",
isAvailable = true,
UserId = 2
},
Product = new Product {
Category = new Category {
CategoryId = 2,
Name = "Categorie2"
},
Name = "Testproduct2",
Price = 3.10M,
Visible = true
}
}
}
}
};
// Create mock units of work
var mockData = new Mock<FakeContext>();
mockData.Setup(m => m.Transactions).Returns(memoryTransactionItems);
// Setup controller
trController = new TransactionController(mockData.Object);
}
[TestMethod]
public void TestTransactionIndex()
{
// Invoke
var viewResult = trController.Index() as ViewResult;
var transactionsFromView = (IEnumerable<TransactionViewModel>)viewResult.Model;
// Assert
Assert.AreEqual(1, transactionsFromView.Count(),
"The amount of transactions added to the Index View should be 1.");
}
}
索引方法中的查询包括以下行:
db.Transactions.Include(t => t.User)
查询的Select部分使用Transaction
类中的User
属性来填充TransactionViewModel
,如中所示
User = group.FirstOrDefault().User.FullName,
如果事务中的用户属性为null,则该行将抛出一个NullReferenceException。因此,当使用伪对象在单元测试中执行时,您需要该查询的结果包含NOTNULL用户属性
我不确定伪上下文和dbset是如何工作的,但最简单的方法是在伪memoryTransactionItems
中填充事务的用户属性
您还可以尝试在下一个代码段中添加一个假的users dbset(我假设您的EF上下文中有一个users dbset):
var memoryUsers=new FakeDbSet
{
新用户{UserId=1,…},
...
};
mockData.Setup(m=>m.Users).Returns(memoryUsers);
您可以从中发布构造函数吗TransactionController@user1511384对完成。在您的索引方法中,您有db.Transactions.Include(t=>t.User)
,您是否尝试过用一组假用户配置假上下文?因为select有一行User=group.FirstOrDefault().User.FullName,
,如果用户为null,该行将给出null引用。类似于mockData.Setup(m=>m.Users).Returns(..)
如果这不起作用,您可以尝试在您的伪事务中填充User属性。谢谢Daniel,这确实是问题所在。Cool@user2609980,让我将其作为答案发布,以便您可以接受它。你刚刚配置了一个假的用户数据库集?
db.Transactions.Include(t => t.User)
User = group.FirstOrDefault().User.FullName,
var memoryUsers = new FakeDbSet<User>
{
new User{ UserId = 1, ... },
...
};
mockData.Setup(m => m.Users).Returns(memoryUsers);