【问题标题】:Moq - Create mocked instance for constructor injected objectMoq - 为构造函数注入对象创建模拟实例
【发布时间】:2013-11-17 16:21:11
【问题描述】:

问题

我想为Credentials 类创建一个单元测试,在执行Calculate() 方法后验证给定凭据的密码,它等于由实现IPasswordCalculator 接口的对象计算的密码。

实际上,我创建的模拟对象在调用Calculate(ICredentials) 方法时返回string.Empty 值,而不是Pa$$w0rd,这将是所需的返回值。

那么……

  • 如何在无需手动创建存根类的情况下实现此测试?
  • 如何在模拟对象上定义回调方法以始终返回Pa$$w0rd

提前致谢。

代码

IPPasswordCalculator 界面

/// <summary>
///     The password calculator interface.
/// </summary>
public interface IPasswordCalculator
{
    /// <summary>
    /// Calculates the user password using 
    /// <paramref name="credentials"/> instance.
    /// </summary>
    /// <param name="credentials">
    /// <see cref="ICredentials"/> to perform the calculation.
    /// </param>
    void Calculate(ICredentials credentials);
}

ICredentials 接口

/// <summary>
///     The Credentials interface.
/// </summary>
public interface ICredentials
{
    /// <summary>
    ///     Gets or sets the user password.
    /// </summary>
    string Password { get; set; }

    /// <summary>
    ///     Gets the user name.
    /// </summary>
    string Username { get; }

    /// <summary>
    ///     Calculates the password.
    /// </summary>
    void Calculate();
}

凭据实施

/// <summary>
///     User credentials.
/// </summary>
public sealed class Credentials : ICredentials
{
    /// <summary>
    ///     Initializes a new instance of the <see cref="Credentials" /> class.
    /// </summary>
    /// <param name="passwordCalculator">
    ///     The credentials calculator.
    /// </param>
    /// <param name="username">
    ///     The user name.
    /// </param>
    public Credentials(IPasswordCalculator passwordCalculator, string username)
    {
        this.Calculator = passwordCalculator;
        this.Username = username;
        this.Password = string.Empty;
    }

    /// <summary>
    ///     Calculates the password.
    /// </summary>
    public void Calculate()
    {
        if (null != this.Calculator)
        {
            this.Calculator.Calculate(this);
        }
    }
}

测试

    /// <summary>
    /// Calculate should set password value expected using calculator.
    /// </summary>
    [TestMethod]
    public void CalculateShouldSetPasswordValueExpectedUsingCalculator()
    {
        ICredentials credentials = null;
        var repo = new MockRepository(MockBehavior.Default);
        var mock = repo.Create<IPasswordCalculator>();
        mock.Setup(x => x.Calculate(credentials))
            .Callback(() => { credentials.Password = "Pa$$w0rd"; });

        IPasswordCalculator calculator = mock.Object;

        credentials = new Credentials(calculator, "Me");
        credentials.Calculate();

        Assert.AreEqual("Pa$$w0rd", credentials.Password);  // Fail
    }

【问题讨论】:

    标签: c# unit-testing dependency-injection moq


    【解决方案1】:

    我认为您需要在调用 mock.Setup() 之前初始化凭证变量。使用您的代码,Moq 需要调用 credentials.Calculate(null)。

    【讨论】:

      【解决方案2】:

      您需要通过以下方式设置您的模拟

      mock.Setup(x => x.Calculate(It.IsAny<ICredentials>()))
          .Callback((ICredentials c) => { c.Password = "Pa$$w0rd"; });
      

      因此你告诉它“无论你得到什么ICredentials 作为Calculate 方法的参数,将它的Password 设置为'Pa$$word'”

      【讨论】:

      • 简单有效。谢谢!
      • 只是想以同样的方式修改我的答案,就像我看到你的一样。是的,这样更好。
      猜你喜欢
      • 2016-11-19
      • 1970-01-01
      • 1970-01-01
      • 2011-02-27
      • 2011-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多