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);