是否可以对依赖于 NHibernate Detached Criteria 的方法进行单元测试?
我尝试使用 Moq 对使用 DetachedCriteria 类的存储库上的方法进行单元测试。但我遇到了一个问题,即我实际上无法模拟内置的内部 Criteria 对象。有什么方法可以模拟独立的标准吗?
测试方法
[Test]
[Category("UnitTest")]
public void FindByNameSuccessTest()
{
//Mock hibernate here
var sessionMock = new Mock<ISession>();
var sessionManager = new Mock<ISessionManager>();
var queryMock = new Mock<IQuery>();
var criteria = new Mock<ICriteria>();
var sessionIMock = new Mock<NHibernate.Engine.ISessionImplementor>();
var expectedRestriction = new Restriction {Id = 1, Name="Test"};
//Set up expected returns
sessionManager.Setup(m => m.OpenSession()).Returns(sessionMock.Object);
sessionMock.Setup(x => x.GetSessionImplementation()).Returns(sessionIMock.Object);
queryMock.Setup(x => x.UniqueResult<SopRestriction>()).Returns(expectedRestriction);
criteria.Setup(x => x.UniqueResult()).Returns(expectedRestriction);
//Build repository
var rep = new TestRepository(sessionManager.Object);
//Call repostitory here to get list
var returnR = rep.FindByName("Test");
Assert.That(returnR.Id == expectedRestriction.Id);
}
存储库类
public class TestRepository
{
protected readonly ISessionManager SessionManager;
public virtual ISession Session
{
get { return SessionManager.OpenSession(); }
}
public TestRepository(ISessionManager sessionManager)
{
}
public SopRestriction FindByName(string name)
{
var criteria = DetachedCriteria.For<Restriction>().Add<Restriction>(x => x.Name == name)
return criteria.GetExecutableCriteria(Session).UniqueResult<T>();
}
}
注意,我在这里也使用“NHibernate.LambdaExtensions”和“Castle.Facilities.NHibernateIntegration”。任何帮助将不胜感激。
本质上,我在返回的对象的断言上收到了空引用异常。因此我认为我没有正确连接标准。但我不认为我可以做到这一点,因为该标准是在我的存储库中创建的独立标准的私有字段!
I have tried to use Moq to unit test a method on a repository that uses the DetachedCriteria class. But I come up against a problem whereby I cannot actually mock the internal Criteria object that is built inside. Is there any way to mock detached criteria?
Test Method
[Test]
[Category("UnitTest")]
public void FindByNameSuccessTest()
{
//Mock hibernate here
var sessionMock = new Mock<ISession>();
var sessionManager = new Mock<ISessionManager>();
var queryMock = new Mock<IQuery>();
var criteria = new Mock<ICriteria>();
var sessionIMock = new Mock<NHibernate.Engine.ISessionImplementor>();
var expectedRestriction = new Restriction {Id = 1, Name="Test"};
//Set up expected returns
sessionManager.Setup(m => m.OpenSession()).Returns(sessionMock.Object);
sessionMock.Setup(x => x.GetSessionImplementation()).Returns(sessionIMock.Object);
queryMock.Setup(x => x.UniqueResult<SopRestriction>()).Returns(expectedRestriction);
criteria.Setup(x => x.UniqueResult()).Returns(expectedRestriction);
//Build repository
var rep = new TestRepository(sessionManager.Object);
//Call repostitory here to get list
var returnR = rep.FindByName("Test");
Assert.That(returnR.Id == expectedRestriction.Id);
}
Repository Class
public class TestRepository
{
protected readonly ISessionManager SessionManager;
public virtual ISession Session
{
get { return SessionManager.OpenSession(); }
}
public TestRepository(ISessionManager sessionManager)
{
}
public SopRestriction FindByName(string name)
{
var criteria = DetachedCriteria.For<Restriction>().Add<Restriction>(x => x.Name == name)
return criteria.GetExecutableCriteria(Session).UniqueResult<T>();
}
}
Note I am using "NHibernate.LambdaExtensions" and "Castle.Facilities.NHibernateIntegration" here as well. Any help would be gratefully appreciated.
Essentially I am getting a null reference exception on the assert of the object returned. Thus I assume that I have not connected up the criteria correctly. But I don't think I can do this because the criteria is a private field of the Detached Criteria which is created inside my repository!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
老实说,我很久以前就放弃了尝试对任何涉及数据库的内容进行单元测试。
启动内存中的 Sqlite 数据库并运行实际测试要容易得多。或者,如果您希望针对真实数据库运行它们,那么只需将它们移至集成测试中,该测试仅在您签入源代码管理时运行。
Honestly I gave up on trying to unit test anything that touches the database a long time ago.
It's so much easier to spin up an in memory Sqlite db and just run the actual tests. Or if you would rather run them against the real database then just move them into your integration tests that only get ran when you do a checkin to source control.
我认为您错过了在这种情况下使用模拟的意义。您想要模拟的是方法
,因此您可以返回您想要的任何类型的
SopRestriction
而不必担心它正在查询 NHibernate。模拟任何类型的数据上下文都是毫无意义的,因为你永远不会获得任何价值。
最简单的方法是从 TestRepository 中提取一个接口,例如 ITestRepository,然后使依赖关系图的其余部分依赖于 ITestRepository,并且您可以在单元测试中轻松模拟存储库本身。
跟进:关于您想要验证存储库内的方法调用的响应,我建议将所有 NHibernate 特定用法包装到没有任何类型参数或返回的方法本身中NHibernate 特定的,因此您可以模拟这些方法并期望它们能够工作。这就是为什么单元测试在这个阶段的价值较低,因为你没有得到太多。按照你所说的,我根本不会嘲笑他们,而是会让他们进行完整的“集成”测试,接触数据库或做他们需要做的事情。我仍然认为这些是单元测试,即使 TDD 纯粹主义者会说它们是集成测试。
I think you're missing the point of using mocking in this situtation. What you want to mock is the method
So then you can return any type of
SopRestriction
you want and not worry about the fact it's querying NHibernate.It's pointless to ever mock any type of datacontext because you'll never gain any value.
The easiest way to do this would be to extract an interface from TestRepository so like ITestRepository and then make the rest of your dependency graph dependent on ITestRepository and you can mock the repository itself easily in your unit tests.
Follow up: Regarding your response about wanting to verify method calls inside your repository what I would reccomend is wrapping all of the NHibernate specific usage into methods themselves that don't have any type of parameter or return that is NHibernate specific so then you can mock those methods and just expect them to work. This is why unit testing is less valuable at this stage because you don't gain much. With what you said I wouldn't mock them at all but would make them full "integration" tests that touch the database or do what they need to do. I still consider these to be unit tests even if TDD purists would say they're integration tests.