mrb*_*lah 2 c# nhibernate unit-testing moq
我想测试的类是我的ArticleManager类,特别是LoadArticle方法:
public class ArticleManager : IArticleManager
{
private IArticle _article;
public ArticleManger(IDBFactory dbFactory)
{
_dbFactory = dbFactory;
}
public void LoadArticle(string title)
{
_article = _dbFactory.GetArticleDAO().GetByTitle(title);
}
}
Run Code Online (Sandbox Code Playgroud)
我的ArticleDAO看起来像:
public class ArticleDAO : GenericNHibernateDAO<IArticle, int>, IArticleDAO
{
public virtual Article GetByTitle(string title)
{
return Session.CreateCriteria(typeof(Article))
.Add(Expression.Eq("Title", title))
.UniqueResult<Article>();
}
}
Run Code Online (Sandbox Code Playgroud)
[SetUp]
public void SetUp()
{
_mockDbFactory = new Mock<IDBFactory>();
_mockArticleDao = new Mock<ArticleDAO>();
_mockDbFactory.Setup(x => x.GetArticleDAO()).Returns(_mockArticleDao.Object);
_articleManager = new ArticleManager(_mockDbFactory.Object);
}
[Test]
public void load_article_by_title()
{
var article1 = new Mock<IArticle>();
_mockArticleDao.Setup(x => x.GetByTitle(It.IsAny<string>())).Returns(article1.Object);
_articleManager.LoadArticle("some title");
Assert.IsNotNull(_articleManager.Article);
}
Run Code Online (Sandbox Code Playgroud)
单元测试失败,对象_articleManager.Article返回NULL.
我做的一切都正确吗?
这是我的第一次单元测试之一,所以我可能错过了一些明显的东西?
我遇到的一个问题是,我想模仿IArticleDao,但由于类ArticleDao也继承自抽象类,如果我只是嘲笑IArticleDao那么GenericNHibernateDao中的方法不可用?
前言:我不熟悉在这里使用Moq(Rhino Mocks用户)所以我可能会错过一些技巧.
我在努力遵循这里的一些代码; 正如马克·西曼(Mark Seemann)所指出的那样,我不明白为什么这种情况甚至可以在目前的状 你能仔细检查代码吗?
有一点需要注意的是,你正在向文章管理员注入IDBFactory的模拟.然后你进行链接调用:
_article = _dbFactory.GetArticleDAO().GetByTitle(title)
Run Code Online (Sandbox Code Playgroud)
你还没有提供实现GetArticleDAO.你只是嘲笑了电话后LoadByTitle发生的事情.测试中模拟和链接调用的组合通常表明测试即将变得痛苦.GetARticleDAO
得墨忒耳定律
突出点在这里:尊重得墨忒耳法则.ArticleManager使用IDBFactory返回的IArticleDAO.除非IDBFactory做了非常重要的事情,否则你应该将IArticleDAO注入到ArticleManager中.
Misko雄辩地解释了为什么挖掘合作者是一个坏主意.这意味着你有一个额外的挑战步骤来设置,也使API更加混乱.
此外,为什么将返回的文章作为字段存储在ArticleManager中?你能回来吗?
如果可以进行这些更改,它将简化代码并使测试变得更容易.
您的代码将变为:
public class ArticleManager : IArticleManager
{
private IArticleDAO _articleDAO
public ArticleManger(IArticleDAO articleDAO)
{
_articleDAO = articleDAO;
}
public IArticle LoadArticle(string title)
{
return _articleDAO.GetByTitle(title);
}
}
Run Code Online (Sandbox Code Playgroud)
然后你会有一个更简单的API,它会更容易测试,因为嵌套已经消失了.
依赖持久性使测试更容易
在我是单元测试与持久性机制交互的代码的情况下,我通常使用存储库模式并创建手动,伪造的内存存储库来帮助进行测试.它们通常也很容易编写 - 它只是实现IArticleRepository接口的字典的包装器.
使用这种技术允许您的ArticleManager使用伪持久性机制,其行为与数据库非常相似,以便进行测试.然后,您可以轻松地使用可帮助您以无痛方式测试ArticleManager的数据填充存储库.
模拟框架确实是很好的工具,但它们并不总是适合建立和验证复杂或连贯的交互; 如果你需要在一次测试中模拟/存储多个东西(特别是嵌套的东西!),这通常表明测试是过度指定的,或者手动测试双重是更好的选择.
测试很难
......而且在我看来,如果你从模拟框架开始,那就更加困难了.我已经看到很多人因为在引擎盖下发生的"魔法"而与嘲弄框架结合在一起.其结果是,我一般主张停留远离他们,直到你满意手卷存根/嘲笑/赝品/间谍等.
| 归档时间: |
|
| 查看次数: |
5235 次 |
| 最近记录: |