使用MOQ嵌套类和单元测试单元测试接口C#

时间:2017-11-09 09:14:28

标签: c# unit-testing moq

您好我有以下接口及其实现。现在,我想对Send()方法进行单元测试,该方法实际上会将消息推送到队列中。 由于我是MoQ的新手,不知道如何完成它。

public interface IAdapter 
{
    IChannel UseQueue(QueueDetail queueDetail);
}
public interface IChannel
{
    void Send(string key, byte[] message);
}

public class AdapternServiceBus : IAdapter
{   
    readonly IConnection connection;
    readonly IModel channel;

    public AdapternServiceBus(IConnection connection, IModel channel)
    {
        this.connection = connection;     
        this.channel = channel;
    }

    public IChannel BindAndUseQueue(QueueDetail queueDetail)
    {
        // Logic of creating and binding queue
        return new ServiceBusChannel(this, queueDetail.QueueName);
    }

    public IModel GetChannel()
    {
        return channel;
    }
}

public class ServiceBusChannel : IChannel
{
    readonly string containerName;
    IModel channel;

    public ServiceBusChannel(AdapternServiceBus adapter, string containerName)
    {   
        this.containerName = containerName;
        channel = adapter.GetChannel();
    }

    public void Send(string key, byte[] message)
    {
        // Publish the message
        channel.BasicPublish(exchangeName, key, null, message);
    }
}

通过工厂,我们决定我们需要连接哪种类型的框架,并且在工厂内,我们打开一个传递给下一个类的连接,以便可以使用它来创建和绑定队列。 IChannel的实现是用于实际与队列和主题交谈的主要类。

2 个答案:

答案 0 :(得分:3)

您想在Send课程中测试ServiceBusChannel方法。

因此,在您的测试中,您应该实例化这个实际的具体类。

要实例化ServiceBusChannel,您需要AdapterServiceBus,以便设置channel变量。

这里,问题是您依赖于具体的AdapterServiceBus类,因此您无法模拟它。您应该依赖于公开您要模拟的实际行为的接口

IAdpaterServiceBus之类的东西,声明GetChannel();(编辑) 或声明GetChannel()作为已存在的IAdapter interace的方法< / em>的

然后你可以嘲笑这个:

var mockedAdapter = new Mock<IAdapterServiceBus>();

var mockedAdapter = new Mock<IAdapter>(); // if you added GetChannel() to IAdapter

然后模拟GetChannel()的行为:

mockedAdapter.Setup(x => x.GetChannel())
     .Returns( /* some mocked string value for your channel */);

然后您可以将其传递给ServiceBusChannel构造函数(已修改,因此它接受抽象IAdapterServiceBus IAdapter)而不是具体实例)

var service = new ServiceBusChannel(mockedAdapter.Object, containerName);

答案 1 :(得分:2)

以下最小示例显示了如何通过提供必要的依赖关系来对ServiceBusChannel.Send方法进行单元测试,以允许执行测试。它基于原始问题提供的示例。

[TestClass]
public class ServiceBusChannel_Should {
    [TestMethod]
    public void SendMessage() {
        //Arrange
        var channel = Mock.Of<IModel>();
        var connection = Mock.Of<IConnection>();
        var adapter = new AdapternServiceBus(connection, channel);
        var key = "somekey";
        var message = Encoding.UTF8.GetBytes("Hello World");
        var subject = new ServiceBusChannel(adapter, "containerName");

        //Act
        subject.Send(key, message);

        //Assert
        Mock.Get(channel).Verify(_ => _.BasicPublish(It.IsAny<string>(), 
                                         It.IsAny<string>(), 
                                         It.IsAny<bool>(), 
                                         It.IsAny<IBasicProperties>(), 
                                         It.IsAny<byte[]>())
                                  , Times.AtLeastOnce());
    }
}

注意:Moq框架用于模拟抽象依赖项。他们的Quickstart提供了如何使用框架的示例。

虽然我认为测试中的主题不应该与具体结果相结合,但AdapternServiceBus可以用作模拟依赖项的入口点,如上所示。您可以修改以满足您的特定需求,因为我假设提供的代码不是使用的实际代码,而是一个示例。