我想测试以下方法:
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());
}
该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; }
}
该TransactionViewModel
如下外观:
public class TransactionViewModel
{
public string User { get; set; }
public int UserId { get; set; }
public decimal Total { get; set; }
}
并用于计算Total
属于用户的不同交易的金额。
为了测试此方法,我在以下安装程序中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 = "[email protected]",
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 = "[email protected]",
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.");
}
}
当我运行时,TestTransactionIndex
出现以下错误:
测试名称:TestTransactionIndex测试结果:测试失败持续时间:0:00:30.6276475
结果消息:测试方法Tests.Controllers.TransactionControllerTest.TestTransactionIndex引发异常:System.NullReferenceException:对象引用未设置为对象的实例。结果StackTrace:位于lambda_method(Closure,IGrouping
2 ) at System.Linq.Enumerable.WhereSelectEnumerableIterator
2.MoveNext()
位于System.Collections.Generic.List1..ctor(IEnumerable
1集合处)
在System.Linq.Enumerable.ToList [TSource](IEnumerable`1源)在Controllers.TransactionController.Index()
我发现这很奇怪,因为我以正确的方式设置了模拟单元。希望有人能解释我如何正确地将FakeDbSet<Transaction>
视图发送给视图而不获取视图NullReferenceException
。
/编辑根据要求,以下是这些的构造函数TransactionController
:
private IContext _context;
public TransactionController()
{
_context = new Context();
}
public TransactionController(IContext context)
{
_context = context;
}
您的索引方法中的查询包括以下行:
db.Transactions.Include(t => t.User)
查询的Select部分正在使用类中的User
属性Transaction
来填充TransactionViewModel
as
User = group.FirstOrDefault().User.FullName,
如果Transaction中的User属性为null,则该行将引发NullReferenceException。因此,当您在使用假对象的单元测试中执行该查询时,您需要该查询的结果包含一个不为null的User属性。
我不知道你的假背景和DbSets工作,但最简单的事情要尝试如何填充交易的用户属性在你的假memoryTransactionItems
。
您还可以尝试在下一个代码段中添加伪造的用户dbset(我假设您在EF上下文中有一个Users DbSet):
var memoryUsers = new FakeDbSet<User>
{
new User{ UserId = 1, ... },
...
};
mockData.Setup(m => m.Users).Returns(memoryUsers);
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句