0

当我运行这个测试时,我得到一个“Assert.Fail failed.Assert.AreEqual failed.Expected:.Actual:.”

在错误消息末尾没有“实际:”的情况下,如何使此测试通过或失败?我使用“Assert.Fail(ex.Message);” 在其他几个测试中,所以我无法直接更改消息。

    [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);
          var isAuthenticated = prov.ValidateUser(user.UserName, "12345");

          Assert.IsTrue(isAuthenticated);
          Assert.AreEqual(user.UserName, "testUserX");
          Assert.AreEqual(user.Email, "test.userx@abc.com");
          Assert.IsTrue(user.CreationDate==DateTime.Now);
          //TODO Asserts

       }

       catch (Exception ex)
       {
          LogMessage(ex);
          Assert.Fail(ex.Message);
       }
    }
4

3 回答 3

5

Well, as far as I understood, you want to specify custom fail messsage for your asserts?

OK,

Assert.AreEqual( object expected, object actual, string message );

More here

You can even create some special failing assert, read here about CustomAsserts

IMO, you do not need that try-catch block, just add custom messages to your asserts

于 2013-05-13T18:21:15.160 回答
4

添加的附加信息:单元测试(通常)应该只检查一个组件。对于这个测试,我将删除验证用户的调用,因为它应该是它自己的测试方法中的检查。

这意味着两种测试方法 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);.

这是您在尝试测试提供程序时会遇到的次要问题。现在用你想要的消息抛出异常将允许你完全自定义你的消息。

于 2013-05-13T18:41:54.273 回答
1

"Actual" is coming from the ex.Message. This is read-only.

You could do some string manipulation though, something like:

catch (Exception ex)
{
    string message = ex.Message.Substring(0, ex.Message.IndexOf("Actual:"));
    LogMessage(message);
    Asset.Fail(ex.Message);
}
于 2013-05-13T18:21:41.957 回答