添加的附加信息:单元测试(通常)应该只检查一个组件。对于这个测试,我将删除验证用户的调用,因为它应该是它自己的测试方法中的检查。
这意味着两种测试方法
CreateUser_IsSuccessful_IfCreatingUserThatDoesNotExist()
ValidateUser_Authenticates_IfGivenCorrectUsernameAndPassword()
这比 TestCreateUser 方法名称更具描述性,并允许您进行更细粒度的测试。下一个测试可能是CreateUser_Fails_IfRecreatingExistingUser()
。
很难给出真正好的建议,因为我们不知道您正在从事的项目的要求。如果您必须具有自定义输出,那么我最初建议的内容将起作用(但这不是最佳实践,对我来说有点像黑客攻击)。更好的解决方案更像是这样的:
[TestMethod]
public void TestCreateUser()
{
AsaMembershipProvider prov = this.GetMembershipProvider();
//call get user
MembershipCreateStatus status;
MembershipUser user = prov.CreateUser("testUserX", "12345", "test.UserX@abc.com", "", "", true, null, out status);
//Assert.AreNotEqual(status, MembershipCreateStatus.Success);
if (status != MembershipCreateStatus.Success)
Assert.Fail("Error message you want goes here for this case.");
var isAuthenticated = prov.ValidateUser(user.UserName, "12345");
//Assert.IsTrue(isAuthenticated);
if (!isAuthenticated)
Assert.Fail("Error message you want goes here for this case.");
//Assert.AreEqual(user.UserName, "testUserX");
if (user.UserName != "testUserX")
Assert.Fail("Error message you want goes here for this case.");
//Assert.AreEqual(user.Email, "test.userx@abc.com");
if (user.Email != "test.userx@abc.com")
Assert.Fail("Error message you want goes here for this case.");
//Assert.IsTrue(user.CreationDate==DateTime.Now);
if (user.CreationDate != DateTime.Now)
Assert.Fail("Error message you want goes here for this case.");
}
它自定义了错误消息并删除了不必要的笨重的 try catch。
我将保留之前的原始输出,因为答案已被接受,但我同意不应以这种方式使用 try catch 的评论(因此进行了上面的更正)。我在测试中使用 try catch 的唯一一次是,如果我正在专门测试一个场景,该场景会引发特定类型的异常,如果违反业务规则就会引发该异常
try
{
methodToThrowException();
Assert.Fail("BusinessSpecificException was not thrown by the code.");
}
catch (BusinessSpecificException ex)
{
//Asserts go here
}
如果您想将所有断言汇集到 catch 块,并且您想自定义错误输出,则可以这样实现:
[TestMethod]
public void TestCreateUser()
{
try
{
AsaMembershipProvider prov = this.GetMembershipProvider();
//call get user
MembershipCreateStatus status;
MembershipUser user = prov.CreateUser("testUserX", "12345", "test.UserX@abc.com", "", "", true, null, out status);
//Assert.AreNotEqual(status, MembershipCreateStatus.Success);
if (status != MembershipCreateStatus.Success)
throw new Exception("Error message you want goes here for this case.");
var isAuthenticated = prov.ValidateUser(user.UserName, "12345");
//Assert.IsTrue(isAuthenticated);
if (!isAuthenticated)
throw new Exception("Error message you want goes here for this case.");
//Assert.AreEqual(user.UserName, "testUserX");
if (user.UserName != "testUserX")
throw new Exception("Error message you want goes here for this case.");
//Assert.AreEqual(user.Email, "test.userx@abc.com");
if (user.Email != "test.userx@abc.com")
throw new Exception("Error message you want goes here for this case.");
//Assert.IsTrue(user.CreationDate==DateTime.Now);
if (user.CreationDate != DateTime.Now)
throw new Exception("Error message you want goes here for this case.");
//TODO Asserts
}
并且您的测试方法仍将运行 Assert.Fail 部分。幕后的断言方法在内部做着与此非常相似的事情(尽管可能抛出派生的异常类型而不是基类)。
作为高级建议,我会说对提供者进行单元测试将非常困难。我过去创建了一个自定义的,以允许我控制输入和输出的方式重写它是一场噩梦。我必须做的是提供一个构造函数,它允许我为我的外部依赖项传递接口以允许我编写我的测试。当我这样做时,我就能够编写测试,例如
ReturnsCreatedUser_IfCreationIsSuccessful()
或者ReturnsInvalidPassword_IfPasswordIsInvalid()
断言看起来像这样:Assert.AreEqual(MembershipCreateStatus.Success, _status);
Assert.IsNotNull(response);
,
和
Assert.AreEqual(MembershipCreateStatus.InvalidPassword, _status);
.
这是您在尝试测试提供程序时会遇到的次要问题。现在用你想要的消息抛出异常将允许你完全自定义你的消息。