这是Moq的正确用法吗?

复杂

我有以下界面,为我提供了使用Cookie的方法:

/// <summary>
/// Provides an interface that makes it easy to work with cookies.
/// </summary>
public interface ICookies
{
    #region Properties

    /// <summary>
    /// Gets or sets the value of the <see cref="ICookies"/>.
    /// </summary>
    /// <param name="name">The name of the cookie.</param>
    /// <returns>A string that represents the value in this cookie.</returns>
    string this[string name] { get; set; }

    #endregion

    #region Methods

    /// <summary>
    /// Writes a new cookie.
    /// </summary>
    /// <param name="name">The name of the cookie.</param>
    /// <param name="expiration">The <see cref="DateTime"/> when this cookie expires.</param>
    /// <param name="value">The value that the cookie should have.</param>
    void Create(string name, string value, DateTime expiration);

    /// <summary>
    /// Checks wether a cookie with a specific name does exist.
    /// </summary>
    /// <param name="name">The name of the cookie.</param>
    /// <returns><see langword="true"/> if the cookie does exists, otherwise, <see langword="false"/>.</returns>
    bool DoesExist(string name);

    #endregion
}

我有一个以下经理,该经理从上面使用ICookie界面来创建cookie。该类如下所示:

/// <summary>
///     Provides an easy way to work with cookies on the server.
/// </summary>
public static class CookieManager
{
    #region Methods

    /// <summary>
    ///     Writes a new cookie on the.
    /// </summary>
    /// <param name="cookies">The <see cref="ICookies" /> that is responsible for working with cookies.</param>
    /// <param name="name">The name of the cookie.</param>
    /// <param name="value">The value of the cookie.</param>
    public static void Write(ICookies cookies, string name, string value)
    {
        if (!Exists(cookies, name))
        {
            cookies.Create(name, value, DateTime.Now.AddYears(1));
        }

        cookies[name] = value;
    }

    /// <summary>
    ///     Reads a cookie.
    /// </summary>
    /// <param name="cookies">The <see cref="ICookies" /> that is responsible for working with cookies.</param>
    /// <param name="name">The name of the cookie to read.</param>
    /// <returns>The value of the cookie.</returns>
    /// <exception cref="KeyNotFoundException">The cookie is not existing.</exception>
    public static string Read(ICookies cookies, string name)
    {
        return cookies[name];
    }

    /// <summary>
    ///     Check if a cookie does exists.
    /// </summary>
    /// <param name="cookies">The <see cref="ICookies" /> that is responsible for working with cookies.</param>
    /// <param name="name">The name of the cookie.</param>
    /// <returns><see langword="true" /> when the cookie does exists, otherwise <see langword="false" />.</returns>
    public static bool Exists(ICookies cookies, string name)
    {
        return cookies.DoesExist(name);
    }

    #endregion
}

现在,我想编写一个模拟cookie接口以确保其通过的单元测试。

我想检查以下内容:

  • 当我调用CookieManager.Write时,应该编写一个cookie,并且应该能够使用CookieManager.Read函数读取它。正确的方法是什么,因为我已经尝试了所有方法(使用Verifyable,Setup,SetupGet,SetupSet)。

非常重要的一点是,我正在与Moq合作。

这是我目前所拥有的:

我有一个不变的第一:

protected const string CookieReturnValue = "ReturnValue";

然后,我得到了ICookie的模拟:

protected override void Arrange()
   {
       cookies = new Mock<ICookies>();

       cookies.Setup(c => c.Create(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DateTime>()));
       cookies.SetupGet(c => c[It.IsAny<string>()]).Returns(CookieReturnValue).Verifiable();
   }

然后执行测试:

protected override void Act()
{
    CookieManager.Write(cookies.Object, "MyCookie", "MyValue");
    CookieManager.Read(cookies.Object, "MyCookie");
}

最后,测试已通过验证:

cookies.Verify();

现在,该测试通过了,但是我不太确定这是否是正确的测试方法,因为在我的模拟中,我将返回常量“ CookieReturnValue”。我应该能够将其设置为在cookies.Setup()方法中作为第二个参数输入的值,其中第二个参数保存cookie的值。

这里的主要问题是,如果我没有编写cookie,测试也会通过。我需要确保只有在编写cookie并再次读取相同的cookie时,测试才能通过。

如果这是正确的测试方法,或者应该在哪里进行调整以确保其正常工作,可以有人吗?

懒惰

您实际上有三个测试。

第一个测试是否CookieManager检查cookie是否存在,如果不存在Create,则调用,然后设置cookie:

var cookies = new Mock<ICookies>();

// there's no cookie
cookies.Setup(c => c.DoesExist(It.IsAny<string>())).Returns(false);

CookieManager.Write(cookies.Object, "MyCookie", "MyValue");

// check if create was called with the right parameters
cookies.Verify(c => c.Create("MyCookie", "MyValue", It.IsAny<DateTime>()));
// check if the cookie was set
cookies.VerifySet(mock => mock["MyCookie"] = "MyValue");

第二个测试是否CookieManager检查cookie是否存在,如果存在,则不调用Create,然后设置cookie:

// there's a cookie
cookies.Setup(c => c.DoesExist(It.IsAny<string>())).Returns(true);

CookieManager.Write(cookies.Object, "MyCookie", "MyValue");

// check if create was NOT called
cookies.Verify(c => c.Create(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DateTime>()), Times.Never);
// check if the cookie was set
cookies.VerifySet(mock => mock["MyCookie"] = "MyValue");

第三个测试CookieManager是否尝试读取cookie:

var cookies = new Mock<ICookies>();

CookieManager.Read(cookies.Object, "MyCookie");

// check if the indexer was used with the right key
cookies.Verify(c => c["MyCookie"]);

注意:简单地调用cookies.Verify()本身不会执行任何操作。Verify就像我在示例中所做的那样,您要么必须提供一个委托,要么调用VerifyAll来验证all SetUps

另外,您可以通过使用Times.Once来使这些测试更加严格MockBehavior.Strict

例如,第一个测试也可以写成:

var cookies = new Mock<ICookies>(MockBehavior.Strict);

// there's no cookie
cookies.Setup(c => c.DoesExist("MyCookie")).Returns(false);
// so one has to be created with the right parameters
cookies.Setup(c => c.Create("MyCookie", "MyValue", It.IsAny<DateTime>()));
cookies.SetupSet(mock => mock["MyCookie"] = "MyValue");

CookieManager.Write(cookies.Object, "MyCookie", "MyValue");

cookies.VerifyAll();

另外,我不知道为什么刚用创建CookieManager了cookie值之后又再次设置了cookie值cookies.Create(...)


此外,无需设置模拟返回常量CookieReturnValue,然后检查该模拟是否真的返回了该常量这不会测试CookieManager,而是测试模拟对象本身,这是毫无意义的。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

这是Moq的正确用法吗?

来自分类Dev

这是指令的正确用法吗?

来自分类Dev

这是TransactionSope的正确用法吗?

来自分类Dev

这是display:flex的正确用法吗?

来自分类Dev

异步和承诺-这是正确的用法吗?

来自分类Dev

这是表达式树的正确用法吗?

来自分类Dev

这是C语言中“限制”的正确用法吗?

来自分类Dev

这是Log4Net的正确用法吗

来自分类Dev

这是表达式树的正确用法吗?

来自分类Dev

这是@OneToOne关系中“ mappedBy”的正确用法吗?

来自分类Dev

这是正确的右值引用用法吗?

来自分类Dev

这是 dtos 中构建器模式的正确用法吗?

来自分类Dev

Keras fit_generator(),这是正确的用法吗?

来自分类Dev

这是正确的缓存吗?

来自分类Dev

这是正确的做法吗?

来自分类Dev

这是带有服务/存储库层的MVC中async / await的正确用法吗?

来自分类Dev

这是instanceof的可接受用法吗?

来自分类Dev

这是eval()的可接受用法吗?

来自分类Dev

这是instanceof的可接受用法吗?

来自分类Dev

这是模板的正确行为吗?

来自分类Dev

这是正确的执行方式吗?

来自分类Dev

这是对sleep()的正确使用吗?

来自分类Dev

这是正确的Numpy重塑吗?

来自分类Dev

这是NodeJS的正确行为吗?

来自分类Dev

BigQuery的性能:这是正确的吗?

来自分类Dev

这是正确的 NFA 图吗?

来自分类Dev

原子的这种用法正确吗?

来自分类Dev

这是计数多线程的正确方法吗?

来自分类Dev

C:这是类型转换的正确案例吗?