gpt4 book ai didi

c# - 使用 C# - .Net Core 进行单元测试 RabbitMQ 推送

转载 作者:太空狗 更新时间:2023-10-29 22:56:56 24 4
gpt4 key购买 nike

我已经创建了一个 .net 核心 API,它将消息推送到 RabbitMQ 队列中。我已使用 IOptions.json 文件中读取配置数据并将其添加为依赖项。

下面是我的 Controller 的代码:

[Route("api/[controller]")]
public class RestController : Controller
{
private RabbitMQConnectionDetail _connectionDetail;

public RestController(IOptions<RabbitMQConnectionDetail> connectionDetail)
{
_connectionDetail = connectionDetail.Value;
}

[HttpPost]
public IActionResult Push([FromBody] OrderItem orderItem)
{
try
{
using (var rabbitMQConnection = new RabbitMQConnection(_connectionDetail.HostName,
_connectionDetail.UserName, _connectionDetail.Password))
{
using (var connection = rabbitMQConnection.CreateConnection())
{
var model = connection.CreateModel();
var helper = new RabbitMQHelper(model, "Topic_Exchange");
helper.PushMessageIntoQueue(orderItem.Serialize(), "Order_Queue");
}
}
}
catch (Exception)
{
return StatusCode((int)HttpStatusCode.BadRequest);
}
return Ok();
}
}

连接详细信息类具有以下属性

public class RabbitMQConnectionDetail
{
public string HostName { get; set; }

public string UserName { get; set; }

public string Password { get; set; }
}

现在我想对其进行单元测试,但由于我要针对黑盒对其进行测试,所以我无法想到如何对其进行单元测试并寻求帮助。

连接类

public class RabbitMQConnection : IDisposable
{
private static IConnection _connection;
private readonly string _hostName;
private readonly string _userName;
private readonly string _password;

public RabbitMQConnection(string hostName, string userName, string password)
{
_hostName = hostName;
_userName = userName;
_password = password;
}

public IConnection CreateConnection()
{
var _factory = new ConnectionFactory
{
HostName = _hostName,
UserName = _userName,
Password = _password
};
_connection = _factory.CreateConnection();
var model = _connection.CreateModel();

return _connection;
}

public void Close()
{
_connection.Close();
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_connection.Close();
}
}

~ RabbitMQConnection()
{
Dispose(false);
}
}

辅助类

public class RabbitMQHelper
{
private static IModel _model;
private static string _exchangeName;
const string RoutingKey = "dummy-key.";

public RabbitMQHelper(IModel model, string exchangeName)
{
_model = model;
_exchangeName = exchangeName;
}


public void SetupQueue(string queueName)
{
_model.ExchangeDeclare(_exchangeName, ExchangeType.Topic);
_model.QueueDeclare(queueName, true, false, false, null);
_model.QueueBind(queueName, _exchangeName, RoutingKey);
}

public void PushMessageIntoQueue(byte[] message, string queue)
{
SetupQueue(queue);
_model.BasicPublish(_exchangeName, RoutingKey, null, message);
}

public byte[] ReadMessageFromQueue(string queueName)
{
SetupQueue(queueName);
byte[] message;
var data = _model.BasicGet(queueName, false);
message = data.Body;
_model.BasicAck(data.DeliveryTag, false);
return message;
}
}

最佳答案

将您的 Controller 与实现问题紧密耦合使得很难在没有副作用的情况下测试您的 Controller 。从您提供的示例中,您已经表明您正在封装第 3 部分 API 实现并且仅公开抽象。好的。但是,您还没有创建允许您在测试时模拟它们的抽象。我建议重构 RabbitMQConnection 以实现这一点。

首先要有自己的支持抽象。

public interface IRabbitMQConnectionFactory {
IConnection CreateConnection();
}

并重构RabbitMQConnection如下

public class RabbitMQConnection : IRabbitMQConnectionFactory {
private readonly RabbitMQConnectionDetail connectionDetails;

public RabbitMQConnection(IOptions<RabbitMQConnectionDetail> connectionDetails) {
this.connectionDetails = connectionDetails.Value;
}

public IConnection CreateConnection() {
var factory = new ConnectionFactory {
HostName = connectionDetails.HostName,
UserName = connectionDetails.UserName,
Password = connectionDetails.Password
};
var connection = factory.CreateConnection();
return connection;
}
}

花点时间仔细看看这次重构做了什么。 IOptions 已从 Controller 移至工厂,并且 RabbitMQConnection 也已简化以实现其预期目的。创建连接。

Controller 现在也需要重构

[Route("api/[controller]")]
public class RestController : Controller {
private readonly IRabbitMQConnectionFactory factory;

public RestController(IRabbitMQConnectionFactory factory) {
this.factory = factory;
}

[HttpPost]
public IActionResult Push([FromBody] OrderItem orderItem) {
try {
using (var connection = factory.CreateConnection()) {
var model = connection.CreateModel();
var helper = new RabbitMQHelper(model, "Topic_Exchange");
helper.PushMessageIntoQueue(orderItem.Serialize(), "Order_Queue");
return Ok();
}
} catch (Exception) {
//TODO: Log error message
return StatusCode((int)HttpStatusCode.BadRequest);
}
}
}

再次注意 Controller 的简化。这现在允许工厂在测试时被模拟和注入(inject),并且通过扩展允许模拟被 RabbitMQHelper 使用。您可以将您选择的模拟框架用于依赖项或纯 DI。

关于c# - 使用 C# - .Net Core 进行单元测试 RabbitMQ 推送,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46962304/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com