简体   繁体   English

如何在带有实体框架4.0的MVC4中使用ViewModel模拟方法

[英]How to mock method with ViewModel in MVC4 with Entity Framework 4.0

I want to test the following method: 我想测试以下方法:

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

Here the Transaction model has a list of Orders , has a foreign key to User and some more properties, see: 这里的Transaction模型有一个Orders列表,有一个User的外键和更多的属性,请参见:

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

The TransactionViewModel looks as follows: TransactionViewModel如下所示:

public class TransactionViewModel
{
    public string User { get; set; }
    public int UserId { get; set; }
    public decimal Total { get; set; }
}

and is used to calculate the Total of different transactions belonging to a user. 并用于计算属于用户的不同交易的Total

To test this method I have a FakeDbSet and use a FakeContext (which both work in tests of other controllers) in the following Setup: 为了测试此方法,我在以下安装程序中使用了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.");
    }
}

When I run the TestTransactionIndex I get the following error: 当我运行TestTransactionIndex ,出现以下错误:

Test Name: TestTransactionIndex Test Outcome: Failed Test Duration: 0:00:30.6276475 测试名称:TestTransactionIndex测试结果:测试失败持续时间:0:00:30.6276475

Result Message: Test method Tests.Controllers.TransactionControllerTest.TestTransactionIndex threw exception: System.NullReferenceException: Object reference not set to an instance of an object. 结果消息:测试方法Tests.Controllers.TransactionControllerTest.TestTransactionIndex引发异常:System.NullReferenceException:对象引用未设置为对象的实例。 Result StackTrace: at lambda_method(Closure , IGrouping 2 ) at System.Linq.Enumerable.WhereSelectEnumerableIterator 2.MoveNext() 结果StackTrace:位于2 ) at System.Linq.Enumerable.WhereSelectEnumerableIterator 2.MoveNext()的lambda_method(Closure,IGrouping 2 ) at System.Linq.Enumerable.WhereSelectEnumerableIterator
at System.Collections.Generic.List 1..ctor(IEnumerable 1 collection) 在System.Collections.Generic.List 1..ctor(IEnumerable 1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source) at Controllers.TransactionController.Index() 在System.Linq.Enumerable.ToList [TSource](IEnumerable`1源)在Controllers.TransactionController.Index()

I find this strange since I setup my mock units in the proper way. 我发现这很奇怪,因为我以正确的方式设置了模拟单元。 I hope someone can explain how I can properly send the FakeDbSet<Transaction> to the view and not get a NullReferenceException . 我希望有人能够解释如何正确地将FakeDbSet<Transaction>发送到视图,而不获取NullReferenceException

/Edit As requested, here are the contructors for TransactionController : / Edit根据要求,这是TransactionController的构造函数:

private IContext _context;

public TransactionController()
{
    _context = new Context();
}

public TransactionController(IContext context)
{
    _context = context;
}

The query in your index method includes the line: 索引方法中的查询包括以下行:

db.Transactions.Include(t => t.User)

And the Select part of the query is using the User property in the Transaction class to populate the TransactionViewModel as in 查询的Select部分正在使用Transaction类中的User属性来填充TransactionViewModel如下所示

User = group.FirstOrDefault().User.FullName,

That line will throw a NullReferenceException if the User property in the Transaction is null. 如果Transaction中的User属性为null,则该行将引发NullReferenceException So you need the result of that query to contain a not null User property when executed in your unit test using the fake objects. 因此,当您在使用伪造对象的单元测试中执行查询时,您需要该查询的结果包含不为null的User属性。

I am not sure how your fake context and DbSets work, but the easiest thing to try is to populate the User property of the Transactions in your fake memoryTransactionItems . 我不确定您的虚假上下文和DbSets如何工作,但是最容易尝试的方法是在虚假的memoryTransactionItems填充Transactions的User属性。

You may also try adding a fake users dbset as in the next code snippet (I'm assuming you have a Users DbSet in your EF context): 您还可以尝试在下一个代码片段中添加伪造的用户dbset(我假设您在EF上下文中有一个Users DbSet):

var memoryUsers = new FakeDbSet<User>
{
    new User{ UserId = 1, ... },
    ...
};

mockData.Setup(m => m.Users).Returns(memoryUsers);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM