为什么我的模拟上下文中的 DbSet 为空?
Why are the DbSets in my mocked context null?
最近在研究c#中的单元测试和mocking。对于我选择的工具,我一直使用 Nunit 作为我的测试框架,AutoFac 作为我的 IoC 容器,Moq 用于模拟数据库,以及 Entity Framework 6 用于与所述数据库对话。
在我进行单元测试以判断我是否可以从模拟数据库成功加载时,我收到了 NullReferenceException - 在我的模拟数据库中找不到我要查找的对象。
通过逐步执行我的测试,我能够确定我的 mockSet 以及我的 MockContext 都确实有我在其中设置的测试记录。
Automock 还能够成功创建我正在测试的 class 的对象,并将测试方法所依赖的上下文实例传递给它。但是,此上下文实例中的 DbSet 全部显示为 null,导致我的 Find() 函数失败。
我不确定为什么我的实现中的 DbSet of Characters 为空。据我了解,在创建我的 mockSet 和 mockContext 之后,AutoMock 应该检测我的 mockContext 并将其注入到在此单元测试期间调用我的上下文的任何内容中。不是这样吗?如果是这样,是是什么情况?我应该采取什么步骤来确保我正在测试的 class 注入了我的 mockContext 实例?
这是我的单元测试:
[Test]
public void MySqlDataRoot_LoadCharacterByCharacterID_SingularCharacterObjectReturned()
{
using (var mock = AutoMock.GetLoose())
{
//Attain
//When my code that I'm testing calls for a CharacterContext, return the mock instead.
//Currently, this mock only has a table for Characters set up. trying to get other tables will fail.
//1. Create data to be set in the mock set.
//Tested and confirmed that my test record is being placed into my mockSet and mockContext properly.
List<Character> charList = new List<Character>();
charList.Add(getSampleCharacter());
IQueryable<Character> data = charList.AsQueryable();
//2. Create mock set.
var mockSet = new Mock<DbSet<Character>>();
mockSet.As<IQueryable<Character>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<Character>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<Character>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<Character>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
//3. Create a context based upon the mockSet
var mockContext = new Mock<CharacterContext>();
mockContext.Setup(c => c.Characters).Returns(mockSet.Object);
//Act
//DataRoot is created and has a _characterContext, but the Characters DbSet is null.
var dataRoot = mock.Create<MySqlDataRoot>();
var expected = getSampleCharacter();
var actual = dataRoot.GetCharacterBy_CharacterID(Guid.Parse("11111111-2222-3333-4444-555555555555"));
//Assert
Assert.True(actual != null);
Assert.AreEqual(expected.Character_id, actual.Character_id);
}
}
我认为问题在于您在步骤 3 中创建的模拟 CharacterContext 与模拟 MySqlDataRoot 具有的不同。我没有看到任何可以确保它是同一个实例的东西。再说一次,我不使用自动模拟功能,所以我不熟悉它通常是如何工作的。
找到解决方案,感谢 Plasmadog 指出我的错误,以及 Shafiq Jetha 的回答 here。
我遇到的问题是双重的:首先,正如 Plasmadog 在他的回答中指出的那样,我没有使用我认为已经通过的相同 mockContext。
其次,我缺少 EntityFrameworkTesting.Moq 包,以及 Shafiq 指出的一些关键功能。
对于以后找到此答案的任何人,这里是对我有用的解决方案。
[Test]
public void MySqlDataRoot_LoadCharacterByCharacterID_SingularCharacterObjectReturned()
{
//Arrange
//1. Create the test data.
List<Character> charList = new List<Character>();
charList.Add(getSampleCharacter());
//2. Create a mock set, one that properly responds to EntityFramework's .Find()
var mockSet = new Mock<DbSet<Character>>()
.SetupData(charList, o =>
{
return charList.Single(x => x.Character_id.CompareTo(o.First()) == 0);
});
using (var mockContext = AutoMock.GetLoose())
{
//Act
//3. Use the mockSet to properly create the mockContext.
mockContext.Mock<CharacterContext>().Setup(x => x.Characters).Returns(mockSet.Object);
//4. Create a instance of MySqlDataRoot, injecting mock via the constructor.
IDataRoot toTest = mockContext.Create<MySqlDataRoot>();
var expected = getSampleCharacter();
var Actual = toTest.GetCharacterBy_CharacterID(expected.Character_id);
//Assert
Assert.IsNotNull(expected);
Assert.IsNotNull(Actual);
Assert.AreEqual(Actual.Character_id, expected.Character_id);
}
}
最近在研究c#中的单元测试和mocking。对于我选择的工具,我一直使用 Nunit 作为我的测试框架,AutoFac 作为我的 IoC 容器,Moq 用于模拟数据库,以及 Entity Framework 6 用于与所述数据库对话。
在我进行单元测试以判断我是否可以从模拟数据库成功加载时,我收到了 NullReferenceException - 在我的模拟数据库中找不到我要查找的对象。
通过逐步执行我的测试,我能够确定我的 mockSet 以及我的 MockContext 都确实有我在其中设置的测试记录。
Automock 还能够成功创建我正在测试的 class 的对象,并将测试方法所依赖的上下文实例传递给它。但是,此上下文实例中的 DbSet 全部显示为 null,导致我的 Find() 函数失败。
我不确定为什么我的实现中的 DbSet of Characters 为空。据我了解,在创建我的 mockSet 和 mockContext 之后,AutoMock 应该检测我的 mockContext 并将其注入到在此单元测试期间调用我的上下文的任何内容中。不是这样吗?如果是这样,是是什么情况?我应该采取什么步骤来确保我正在测试的 class 注入了我的 mockContext 实例?
这是我的单元测试:
[Test]
public void MySqlDataRoot_LoadCharacterByCharacterID_SingularCharacterObjectReturned()
{
using (var mock = AutoMock.GetLoose())
{
//Attain
//When my code that I'm testing calls for a CharacterContext, return the mock instead.
//Currently, this mock only has a table for Characters set up. trying to get other tables will fail.
//1. Create data to be set in the mock set.
//Tested and confirmed that my test record is being placed into my mockSet and mockContext properly.
List<Character> charList = new List<Character>();
charList.Add(getSampleCharacter());
IQueryable<Character> data = charList.AsQueryable();
//2. Create mock set.
var mockSet = new Mock<DbSet<Character>>();
mockSet.As<IQueryable<Character>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<Character>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<Character>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<Character>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
//3. Create a context based upon the mockSet
var mockContext = new Mock<CharacterContext>();
mockContext.Setup(c => c.Characters).Returns(mockSet.Object);
//Act
//DataRoot is created and has a _characterContext, but the Characters DbSet is null.
var dataRoot = mock.Create<MySqlDataRoot>();
var expected = getSampleCharacter();
var actual = dataRoot.GetCharacterBy_CharacterID(Guid.Parse("11111111-2222-3333-4444-555555555555"));
//Assert
Assert.True(actual != null);
Assert.AreEqual(expected.Character_id, actual.Character_id);
}
}
我认为问题在于您在步骤 3 中创建的模拟 CharacterContext 与模拟 MySqlDataRoot 具有的不同。我没有看到任何可以确保它是同一个实例的东西。再说一次,我不使用自动模拟功能,所以我不熟悉它通常是如何工作的。
找到解决方案,感谢 Plasmadog 指出我的错误,以及 Shafiq Jetha 的回答 here。
我遇到的问题是双重的:首先,正如 Plasmadog 在他的回答中指出的那样,我没有使用我认为已经通过的相同 mockContext。
其次,我缺少 EntityFrameworkTesting.Moq 包,以及 Shafiq 指出的一些关键功能。
对于以后找到此答案的任何人,这里是对我有用的解决方案。
[Test]
public void MySqlDataRoot_LoadCharacterByCharacterID_SingularCharacterObjectReturned()
{
//Arrange
//1. Create the test data.
List<Character> charList = new List<Character>();
charList.Add(getSampleCharacter());
//2. Create a mock set, one that properly responds to EntityFramework's .Find()
var mockSet = new Mock<DbSet<Character>>()
.SetupData(charList, o =>
{
return charList.Single(x => x.Character_id.CompareTo(o.First()) == 0);
});
using (var mockContext = AutoMock.GetLoose())
{
//Act
//3. Use the mockSet to properly create the mockContext.
mockContext.Mock<CharacterContext>().Setup(x => x.Characters).Returns(mockSet.Object);
//4. Create a instance of MySqlDataRoot, injecting mock via the constructor.
IDataRoot toTest = mockContext.Create<MySqlDataRoot>();
var expected = getSampleCharacter();
var Actual = toTest.GetCharacterBy_CharacterID(expected.Character_id);
//Assert
Assert.IsNotNull(expected);
Assert.IsNotNull(Actual);
Assert.AreEqual(Actual.Character_id, expected.Character_id);
}
}