我的实体如下:
List<Integer>
我有以下测试,我预计会失败,但会通过:
List<Number>
这是public class Class1
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Class2 Class2{ get; set; }
}
public class Class2
{
[Key, ForeignKey("Class1")]
public int Id { get; set; }
public int? Price { get; set; }
public virtual Class1 Class1{ get; set; }
}
方法:
[TestMethod]
public void CreateClass2()
{
var mockSet = new Mock<DbSet<Class2>>();
var mockContext = new Mock<theContext>();
mockContext.Setup(m => m.Class2s).Returns(mockSet.Object);
var service = new Class2Service(mockContext.Object);
service.AddClass2(10, 100);
mockSet.Verify(m => m.Add(It.IsAny<Class2>()), Times.Once());
mockContext.Verify(m => m.SaveChanges(), Times.Once());
}
由于我尚未添加service.AddClass2
并为public class Class2Service
{
private readonly theContext _context;
public CoordService(theContext context)
{
_context = context;
}
public Class2 AddClass2(int id, int? price)
{
var class2 = _context.Class2s.Add(new Class2 { Id = id, Price = price });
_context.SaveChanges();
return class2;
}
}
输入了无效的Class1
(即id
中不存在),{{1}的新条目1}}应该是无效的,因为我用外键约束它。 在我的项目和真实数据库中,它按预期工作并给我错误,但在此测试中它已通过!
答案 0 :(得分:0)
测试使用模拟上下文而不是真实上下文,因此_context.SaveChanges();
实际上什么也不做,因此不会抛出任何异常。
您可以轻松地谷歌如何正确模拟DbContext,例如here或here
此外,我认为单元测试本身应该以不同的方式编写。即你正在测试这里的方法调用,这是添加记录的底层实现。
针对此案例的正确单元测试将检查service.AddClass2(10, 100);
调用是否抛出异常。应该编写一个单独的测试,以查看作为service.AddClass2
方法调用的结果,DbSet中是否出现了新记录,而不是检查是否调用了某些特定方法。
UPD:将IQueriable设置为虚假上下文源的示例。
public static class MockDbSetExtensions
{
public static void SetSource<T>(this Mock<DbSet<T>> mockSet, IList<T> source) where T : class
{
var data = source.AsQueryable();
var iQuryableSet = mockSet.As<IQueryable<T>>();
iQuryableSet.SetupGet(m => m.Provider).Returns(data.Provider);
iQuryableSet.SetupGet(m => m.Expression).Returns(data.Expression);
iQuryableSet.SetupGet(m => m.ElementType).Returns(data.ElementType);
iQuryableSet.Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
}
}
样本用法:
[TestClass]
public class GigRepositoryTests
{
private GigRepository _repository;
private Mock<DbSet<Gig>> _mockGigs;
private Mock<IApplicationDbContext> mockContext;
[TestInitialize]
public void TestInitialize()
{
_mockGigs = new Mock<DbSet<Gig>>();
mockContext = new Mock<IApplicationDbContext>();
_repository = new GigRepository(mockContext.Object);
}
[TestMethod]
public void GetUpcomingGigsByArtist_GigsInThePast_ShouldNotBeReturned()
{
var gig = new Gig() {DateTime = DateTime.Now.AddDays(-1), ArtistId = "1"};
_mockGigs.SetSource(new List<Gig> {gig});
mockContext.SetupGet(c => c.Gigs).Returns(_mockGigs.Object);
var gigs = _repository.GetUpcomingGigs("1");
gigs.Should().BeEmpty();
} }