单元测试Mock的void方法?

时间:2015-06-19 20:50:06

标签: c# unit-testing moq xunit

我想用Mock测试一个void方法。

 public class ConsoleTargetBuilder : ITargetBuilder
{
    private const string CONSOLE_WITH_STACK_TRACE = "consoleWithStackTrace";
    private const string CONSOLE_WITHOUT_STACK_TRACE = "consoleWithoutStackTrace";
    private LoggerModel _loggerModel;
    private LoggingConfiguration _nLogLoggingConfiguration;

    public ConsoleTargetBuilder(LoggerModel loggerModel, LoggingConfiguration nLogLoggingConfiguration)
    {
        _loggerModel = loggerModel;
        _nLogLoggingConfiguration = nLogLoggingConfiguration;
    }

    public void AddNLogConfigurationTypeTagret()
    {
        var consoleTargetWithStackTrace = new ConsoleTarget();
        consoleTargetWithStackTrace.Name = CONSOLE_WITH_STACK_TRACE;
        consoleTargetWithStackTrace.Layout = _loggerModel.layout + "|${stacktrace}";
        _nLogLoggingConfiguration.AddTarget(CONSOLE_WITH_STACK_TRACE, consoleTargetWithStackTrace);

        var consoleTargetWithoutStackTrace = new ConsoleTarget();
        consoleTargetWithoutStackTrace.Name = CONSOLE_WITHOUT_STACK_TRACE;
        consoleTargetWithoutStackTrace.Layout = _loggerModel.layout;
        _nLogLoggingConfiguration.AddTarget(CONSOLE_WITHOUT_STACK_TRACE, consoleTargetWithoutStackTrace);
    }

问题是我不确定如何测试它。我有我的主要代码。

public class ConsoleTargetBuilderUnitTests
{
    public static IEnumerable<object[]> ConsoleTargetBuilderTestData
    {
        get
        {
            return new[]
            {
                 new object[]
                {
                    new LoggerModel(),
                    new LoggingConfiguration(),
                    2
                }
            };
        }
    }
    [Theory]
    [MemberData("ConsoleTargetBuilderTestData")]
    public void ConsoleTargetBuilder_Should_Add_A_Console_Target(LoggerModel loggerModel, LoggingConfiguration nLogLoggingConfiguration, int expectedConsoleTargetCount)
    {
        // ARRANGE
        var targetBuilderMock = new Mock<ITargetBuilder>();
        targetBuilderMock.Setup(x => x.AddNLogConfigurationTypeTagret()).Verifiable();
        // ACT
        var consoleTargetBuilder = new ConsoleTargetBuilder(loggerModel, nLogLoggingConfiguration);
        // ASSERT
        Assert.Equal(expectedConsoleTargetCount, nLogLoggingConfiguration.AllTargets.Count);
    }

请引导我走向正确的方向。

4 个答案:

答案 0 :(得分:3)

在我看来,你根本不需要模拟。您正在测试AddNLogConfigurationTypeTagret。不是构造函数。

[Theory]
[MemberData("ConsoleTargetBuilderTestData")]
public void ConsoleTargetBuilder_Should_Add_A_Console_Target(LoggerModel loggerModel, LoggingConfiguration nLogLoggingConfiguration, int expectedConsoleTargetCount)
{
    // ARRANGE
    var consoleTargetBuilder = new ConsoleTargetBuilder(loggerModel, nLogLoggingConfiguration);
    // ACT
    consoleTargetBuilder.AddNLogConfigurationTypeTagret();
    // ASSERT
    Assert.Equal(expectedConsoleTargetCount, nLogLoggingConfiguration.AllTargets.Count);
}

如果您不想自己调用AddNLogConfigurationTypeTagret,则应在构造函数中调用它。这会将测试更改为:

[Theory]
[MemberData("ConsoleTargetBuilderTestData")]
public void ConsoleTargetBuilder_Should_Add_A_Console_Target(LoggerModel loggerModel, LoggingConfiguration nLogLoggingConfiguration, int expectedConsoleTargetCount)
{
    // ARRANGE
    // ACT
    var consoleTargetBuilder = new ConsoleTargetBuilder(loggerModel, nLogLoggingConfiguration);
    // ASSERT
    Assert.Equal(expectedConsoleTargetCount, nLogLoggingConfiguration.AllTargets.Count);
}

然后类构造函数应为:

public ConsoleTargetBuilder(LoggerModel loggerModel, LoggingConfiguration nLogLoggingConfiguration)
{
    _loggerModel = loggerModel;
    _nLogLoggingConfiguration = nLogLoggingConfiguration;
    AddNLogConfigurationTypeTagret();
}

答案 1 :(得分:2)

  

请指导我正确的方向,我想要两件事。 A)调用该方法。 B)添加了两个目标。所以预期的数量是2。

A)如果您想验证方法AddNLogConfigurationTypeTagret是否已被调用,那么您需要在调用此方法的代码上对其进行测试。例如。类似于ConsoleTargetBuilderClient的类是使用ITargetBuilder 的类的假设示例(在您自己的代码中,您应该拥有类{{}使用{1}}

ConsoleTargetBuilder

然后,您可以进行测试,以验证方法public class ConsoleTargetBuilderClient { private ITargetBuilder _builder; public ConsoleTargetBuilderClient(ITargetBuilder builder) { _builder = builder; } public void DoSomething() { _builder.AddNLogConfigurationTypeTagret(); } } 是否调用方法DoSomething。为此,您可以使用AddNLogConfigurationTypeTagret的模拟,因为您测试与它的交互。测试可能如下所示:

ConsoleTargetBuilder

B)如果您想验证是否已添加目标,则需要测试代码本身(而不是模拟它)。测试可能如下所示:

    public void DoSomething_WhenCalled_AddNLogConfigurationTypeTagretGetsCalled()
    {
        // Arrange
        bool addNLogConfigurationTypeTagretWasCalled = false;
        Mock<ITargetBuilder> targetBuilderMock = new Mock<ITargetBuilder>();
        targetBuilderMock.Setup(b => b.AddNLogConfigurationTypeTagret())
            .Callback(() => addNLogConfigurationTypeTagretWasCalled = true);
        ConsoleTargetBuilderClient client = new ConsoleTargetBuilderClient(targetBuilderMock.Object);

        // Act
        client.DoSomething();

        // Assert
        Assert.IsTrue(addNLogConfigurationTypeTagretWasCalled);
    }

注意:基于Google价值与基于状态的交互测试。

答案 2 :(得分:1)

一般来说,你不应该嘲笑你想要测试的类,你应该嘲笑它的依赖。当你开始嘲笑课程时,你试图测试的东西经常会缠绕在一起导致脆弱的测试,而且很难确定你是在测试你的代码,还是在模拟设置,或者两者兼而有之。 / p>

方法AddNLogConfigurationTypeTagret是您正在测试的类的公共方法,因为@Philip已经说过,您应该只是从测试中调用它,或者应该从构造函数中调用它。如果您的目标是从构造函数中调用它,那么我建议它应该是一个私有方法,除非有理由从类外部调用它。

就测试void方法调用的效果而言,您对该方法引起的状态更改感兴趣。在这种情况下,_nLoggingConfiguration是否有两个目标添加了正确的属性。您没有向我们展示nLoggingConfiguration.AllTargets属性,但我会假设您在测试中使用了Count属性,您只需检查其中的项目即可。列表以确认已将正确的名称和布局添加到正确的目标类型。

答案 3 :(得分:0)

// Assert
targetBuilderMock.Verify(x => x.AddNLogConfigurationTypeTagret(), Times.Once());