如何正确测试? (C#,NUnit,Moq)

时间:2014-03-27 14:59:35

标签: c# unit-testing nunit moq

我希望这不是太模糊,但我只是在学习使用NUnit和Moq进行假货的单元测试。我理解这些概念,并且我可以毫不费力地为执行简单任务的逻辑方法编写测试,例如操纵某些值或调用伪造服务。但我有点试图弄清楚如何测试如下所示的东西,这是一种需要进行数据调用并具有多个依赖关系的方法。

这是我必须根据数据库对用户进行身份验证的类:

class Authenticator: IAuthenticator
{

    private IConnectionHelper _connHelper;

    public Authenticator(IConnectionHelper connHelper)
    {
        _connHelper = connHelper;
    }

    public string UserId { get; set; }
    public string Password { get; set; }
    public UserModel User { get; private set; }

    public bool ValidateUser()
    {

            if (string.IsNullOrEmpty(UserId))
                return false;

            if (string.IsNullOrEmpty(Password))
                return false;

            using (Entities db = new Entities(_connHelper))
            {
                MD5 md5 = MD5.Create();
                byte[] inputBytes = Encoding.ASCII.GetBytes(this.Password);
                byte[] hash = md5.ComputeHash(inputBytes);
                string md5Hash = BitConverter.ToString(hash).ToUpper().Replace("-", string.Empty);

                var query = from u in db.Users
                            where u.UserId.ToUpper().Trim() == this.UserId.ToUpper()
                            where u.CPassword.Trim() == md5Hash
                            select u;

                this.User = query.FirstOrDefault();
            }



        if (this.User == null)
        {
            Log.LogLine(TraceLevel.Verbose, string.Format("Authentication failed for user '{0}'", this.UserId));
            return false;
        }
        else
        {
            Log.LogLine(TraceLevel.Verbose, string.Format("Successfully authenticated user '{0}'", this.UserId));
            return true;
        }
    }


}

我想为此创建一个测试夹具,但我不确定如何处理它。

我可以模拟IConnectionHelper,并测试如果UserId或Password为null / empty,该方法将失败,但这是我能得到的。如果IConnectionHelper是假的,那么我显然无法测试数据库的东西,我不确定我应该做什么。有人可以在这里阐明最佳做法吗?

修改

StuartLc接受的答案肯定让我朝着正确的方向前进。我确实需要为Entity Framework做一些额外的设置工作,基本上使用它作为参考:http://msdn.microsoft.com/en-us/data/dn314429.aspx

1 个答案:

答案 0 :(得分:5)

根据Ryan的评论,您的代码与依赖项EntitiesLog紧密耦合,以便于单元测试(无需诉诸MolesFakes)。

作为一般规则,使用new创建任何实质性依赖关系,或使用static方法(如Log)通常是阻止使用{{1}等框架进行隔离单元测试的罪魁祸首}}

我建议的是重构代码如下:

  1. 通过界面将Moq类(可能是像EF Entities或Linq DbSet这样的ORM工件)创建到工厂中的问题分开。
  2. 可以将DataContext依赖项移至工厂中。
  3. 静态记录器也应该被剥离到一个接口中,一个实例也应该注入你的IConnectionHelper,它的生命周期也由你的IoC容器管理。 AuthenticatorLogger都可以注入
  4. 你应该结束以下的事情:

    EntitiesFactory

    ,您现在可以 public interface IEntitiesFactory { Entities Create(); } public interface ILog { void LogLine(TraceLevel level, string message); } class Authenticator : IAuthenticator { private readonly IEntitiesFactory _entitiesFactory; private readonly ILog _log; public Authenticator(IEntitiesFactory entitiesFactory, ILog log) { _entitiesFactory = entitiesFactory; _log = log; } public string UserId { get; set; } public string Password { get; set; } public UserModel User { get; private set; } public bool ValidateUser() { if (string.IsNullOrEmpty(UserId)) return false; if (string.IsNullOrEmpty(Password)) return false; using (var db = _entitiesFactory.Create()) { MD5 md5 = MD5.Create(); byte[] inputBytes = Encoding.ASCII.GetBytes(this.Password); byte[] hash = md5.ComputeHash(inputBytes); string md5Hash = BitConverter.ToString(hash).ToUpper().Replace("-", string.Empty); var query = from u in db.Users where u.UserId.ToUpper().Trim() == this.UserId.ToUpper() where u.CPassword.Trim() == md5Hash select u; this.User = query.FirstOrDefault(); } if (this.User == null) { _log.LogLine(TraceLevel.Verbose, string.Format("Authentication failed for user '{0}'", this.UserId)); return false; } else { _log.LogLine(TraceLevel.Verbose, string.Format("Successfully authenticated user '{0}'", this.UserId)); return true; } } 出现实体工厂和记录器,现在为找到/未找到的方案提供虚假Mock数据,并验证是否已将正确的内容发送给{{ 1}}等,即

    Users