如何实现XUnit描述性Assert消息?

How to implement XUnit descriptive Assert message?

上下文

在 XUnit github 中我发现了这个:Add Assert.Equal(expected, actual, message) overload #350 (所以开发人员要求一个不存在的重载,见下文)

引用自答案:

We are a believer in self-documenting code; that includes your assertions.

(所以XUnit团队拒绝了)

好的,我知道了。我也相信自记录代码。我还是找不到 此用例:

样本

// Arrange
// Create some external soap service client and its wrapper classes

// Act
// client.SomeMethod();

// Assert
// Sorry, soap service's interface, behaviour and design is *given*
// So I have to check if there is no Error, and 
// conveniently if there is, then I would like to see it in the assertion message

Assert.Equal(0, client.ErrorMessage.Length); // Means no error

// I would like to have the same result what would be the following *N*U*n*i*t* assert:
// Assert.AreEqual(0, client.ErrorMessage.Length, client.ErrorMessage); // Means no error

问题

在这种情况下,我如何在仍然没有此类重载的 XUnit 中实现描述性断言消息?

使用 link 中提供的建议。喜欢 fluent assertions 或创建您自己的断言来包装 Assert.True or Assert.False ,这些断言留下了它们的消息过载。 它被进一步提及

Quote

You can provide messages to Assert.True and .False. If you simply cannot live without messages (and refuse to use a different assertion), you could always fall back to:

Assert.True(number == 2, "This is my message");

Quote:

If you really want to have messages you could add Fluent Assertions or maybe xbehave to your test projects and use their syntax. Fluent Assertions even throws xunit.net exceptions if it encounters its presence.

我遇到了同样的问题。我有一个测试从两个网络 api 中提取数据,然后比较和断言有关内容的各种事情。我开始使用标准的 XUnit 断言,例如:

Assert.Equal(HttpStatusCode.OK, response1.StatusCode);
Assert.Equal(HttpStatusCode.OK, response2.StatusCode);

但是,虽然这提供了一个有用的消息,表明已返回 404,但我们的 build/CI 服务器上的日志并不清楚是哪个服务导致了错误消息。

我最后添加了自己的断言来提供上下文:

public class MyEqualException : Xunit.Sdk.EqualException
{
    public MyEqualException(object expected, object actual, string userMessage)
        : base(expected, actual)
    {
        UserMessage = userMessage;
    }

    public override string Message => UserMessage + "\n" + base.Message;
}

public static class AssertX
{
    /// <summary>
    /// Verifies that two objects are equal, using a default comparer.
    /// </summary>
    /// <typeparam name="T">The type of the objects to be compared</typeparam>
    /// <param name="expected">The expected value</param>
    /// <param name="actual">The value to be compared against</param>
    /// <param name="userMessage">Message to show in the error</param>
    /// <exception cref="MyEqualException">Thrown when the objects are not equal</exception>
    public static void Equal<T>(T expected, T actual, string userMessage)
    {
        bool areEqual;

        if (expected == null || actual == null)
        {
            // If either null, equal only if both null
            areEqual = (expected == null && actual == null);
        }
        else
        {
            // expected is not null - so safe to call .Equals()
            areEqual = expected.Equals(actual);
        }

        if (!areEqual)
        {
            throw new MyEqualException(expected, actual, userMessage);
        }
    }
}

然后我可以做同样的断言:

AssertX.Equal(HttpStatusCode.OK, response1.StatusCode, $"Fetching {Uri1}");
AssertX.Equal(HttpStatusCode.OK, response2.StatusCode, $"Fetching {Uri2}");

并且错误日志给出了实际的、预期的并在我的消息前添加了关于哪个网络api是罪魁祸首的信息。

我意识到我来晚了,但我认为这可能会帮助其他人寻找实用的解决方案,而这些解决方案没有时间 install/learn 另一个测试框架只是为了从测试失败中获取有用的信息.

使用 try/catch 就足够了:

try
{
    Assert.Equal(expectedErrorCount, result.Count);
}
catch (EqualException ex)
{
    throw new XunitException($"{testMsg}\n{ex}");
}