我正在尝试使用.net mvc 4和流畅的nhibernate创建应用程序。
我创建了ProductsFacade
,它负责获取数据并将数据插入数据库。
方法GetProductsByPageAndCategory
用于从数据库中获取记录页面。我想编写单元测试,检查分页是否运行良好。
这很难做到,因为分页必须在单QueryOver
个查询中完成。我不能写单独的方法只获取数据,模拟它并编写单独的分页方法。所以我需要模拟数据库。我使用moq工具进行模拟。
也许有人可以提供一些如何做的提示?或者任何其他替代方法如何解决我的问题?
public class ProductFacade {
//...
public virtual IList<Product> GetProductsByPageAndCategory(
string category,
int pageNumber,
int pageSize)
{
//IList<Product> products = ;
var productsQuery = _session.QueryOver<Product>();
if (category != null)
{
productsQuery.Where(p => p.Category == category);
}
IList<Product> products = productsQuery
.OrderBy(p => p.Id)
.Desc
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize)
.List<Product>();
return products;
}
//...
}
答案 0 :(得分:2)
我也使用moq来模拟NHibernate会话,这是一个如何模拟NHibernate ISession
和ISessionFactory
的非常简单的例子。
var mockSession = new Mock<ISession>();
mockSession.Setup(r => r.Get<ExampleEntity>(It.IsAny<int>()))
.Returns(new ExampleEntity());
var mockSessionFactory = new Mock<ISessionFactory>();
mockSessionFactory.Setup(r => r.OpenSession())
.Returns(mockSession.Object);
var sessionFactory = mockSessionFactory.Object;
// inject mockSessionFactory.Object to your business layer...
// code where ever sessionFactory is used...
// OpenSession now returns the mocked session
using (var session = sessionFactory.OpenSession())
{
//Get of type ExampleEntity will always return whatever you define in your mock
var rs = session.Get<ExampleEntity>(1);
}
要对业务对象使用模拟,您必须以一种可以手动构建它的方式进行设计,以便它使用您的模拟工厂。
通常,如果您使用Unity注入,这很容易。通过统一,您的Business类的构造函数可能会占用会话或工厂或其他...在这种情况下,在您的单元测试中,您可以手动构建目标并将模拟传递给它...
答案 1 :(得分:2)
这是我的替代选择 - 不要模拟数据库。
在我们的测试设置中,每个开发人员的机器上都必须有一个具有给定名称的数据库(例如“CMS_AutoTests”)。测试运行时,它会与此数据库进行交互。
每次测试后运行的TearDown
方法运行一个清除每个表的存储过程,因此每个测试都以一个空数据库开始。
答案 2 :(得分:2)
代码比嘲弄要少得多,更容易理解,更接近真实的东西。它还可以确保您的映射是正确的,因此无需额外的负载保存测试。
//for all tests
static Configuration config;
static ISessionFactory testSessionFactory;
config = Fluently.Configure()
.Database(SQLiteConfiguration.Standard.InMemory().ShowSql().FormatSql())
.Mappings(m => m.AutoMappings.Add(AutoMap.AssemblyOf<Foo>()) // add your mappings here
.BuildConfiguration();
testSessionFactory = config.BuildSessionFactory();
// in test
public ProductTests()
{
session = sf.OpenSession();
new SchemaExport(config).Execute(true, true, false, session.Connection, null);
}
private void InjectSampleData(params object[] objects)
{
foreach (var obj in objects)
{
session.Save(obj);
}
session.Flush();
session.Clear();
}
public void TestThis()
{
InjectSampleData(
new Product() { ... },
new Product() { ... },
new Product() { ... },
new Product() { ... },
);
var products = new ProductFacade(session).GetProductsByPageAndCategory(...);
// assert products match expected subcollection of Injected Data
}