我有以下界面为我提供了一种使用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接口以确保它通过。
我想查看以下内容:
非常重要的是,我正在与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&#39;。我应该能够将其设置为在&#39; cookies.Setup()&#39;中输入的值作为第二个参数。方法,其中第二个参数保存cookie的值。
这里的主要问题是,如果我没有写cookie,测试也会通过。我需要确保测试只是在我写一个cookie然后再次读取相同的cookie时才通过。
如果这是正确的测试方式,或者我应该调整哪些方式以确保它正常工作,那么可以吗?
答案 0 :(得分:2)
你实际上有三次测试。
第一个测试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
验证所有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
在使用cookies.Create(...)
创建Cookie值后再次设置 。
此外,没有必要设置模拟以返回常量CookieReturnValue
,然后检查该常量是否实际返回我的模拟。这不会测试CookieManager
,而是模拟对象本身,这是毫无意义的。