gpt4 book ai didi

c# - 对使用异步调用的 MassTransit 消费者进行单元测试

转载 作者:太空狗 更新时间:2023-10-30 01:18:07 26 4
gpt4 key购买 nike

我们正在为我们的微服务架构使用 MassTransit 异步消息传递(在 RabbitMQ 之上)。

我们在测试反过来进行异步调用的消费者时遇到了问题。

下面的示例显示了一个简单的 MassTransit 消费者,它使用 RestSharp 进行出站调用并利用了 ExecuteAsync 异步方法。

public class VerifyPhoneNumberConsumer : Consumes<VerifyPhoneNumber>.Context
{
IRestClient _restClient;
RestRequest _request;
PhoneNumber _phoneNumber;
PhoneNumberVerificationResponse _responseData;

public VerifyPhoneNumberConsumer(IRestClient client)
{
_restClient = client;
}

public void Consume(IConsumeContext<VerifyPhoneNumber> context)
{
try
{
//we can do some standard message verification/validation here

_restClient.ExecuteAsync<PhoneNumberVerificationResponse>(_request, (response) =>
{
//here we might do some standard response verification

_responseData = response.Data;

_phoneNumber = new PhoneNumber()
{
Number = _responseData.PhoneNumber
};

context.Respond(new VerifyPhoneNumberSucceeded(context.Message)
{
PhoneNumber = _phoneNumber
});
});
}
catch (Exception exception)
{
context.Respond(new VerifyPhoneNumberFailed(context.Message)
{
PhoneNumber = context.Message.PhoneNumber,
Message = exception.Message
});
}
}
}

此示例单元测试可能如下所示:

[TestFixture]
public class VerifyPhoneNumberConsumerTests
{
private VerifyPhoneNumberConsumer _consumer;
private PhoneNumber _phoneNumber;
private RestResponse _response;
private VerifyPhoneNumber _command;

private AutoResetEvent _continuationEvent;
private const int CONTINUE_WAIT_TIME = 1000;

[SetUp]
public void Initialize()
{
_continuationEvent = new AutoResetEvent(false);
_mockRestClient = new Mock<IRestClient>();
_consumer = new VerifyPhoneNumberConsumer(_mockRestClient.Object);
_response = new RestResponse();
_response.Content = "Response Test Content";
_phoneNumber = new PhoneNumber()
{
Number = "123456789"
};
_command = new VerifyPhoneNumber(_phoneNumber);
}

[Test]
public void VerifyPhoneNumber_Succeeded()
{
var test = TestFactory.ForConsumer<VerifyPhoneNumberConsumer>().New(x =>
{
x.ConstructUsing(() => _consumer);
x.Send(_command, (scenario, context) => context.SendResponseTo(scenario.Bus));
});

_mockRestClient.Setup(
c =>
c.ExecuteAsync(Moq.It.IsAny<IRestRequest>(),
Moq.It
.IsAny<Action<IRestResponse<PhoneNumberVerificationResponse>, RestRequestAsyncHandle>>()))
.Callback<IRestRequest, Action<IRestResponse<PhoneNumberVerificationResponse>, RestRequestAsyncHandle>>((
request, callback) =>
{
var responseMock = new Mock<IRestResponse<PhoneNumberVerificationResponse>>();
responseMock.Setup(r => r.Data).Returns(GetSuccessfulVericationResponse());
callback(responseMock.Object, null);
_continuationEvent.Set();
});


test.Execute();

_continuationEvent.WaitOne(CONTINUE_WAIT_TIME);

Assert.IsTrue(test.Sent.Any<VerifyPhoneNumberSucceeded>());
}

private PhoneNumberVerificationResponse GetSuccessfulVericationResponse()
{
return new PhoneNumberVerificationResponse
{
PhoneNumber = _phoneNumber
};
}
}

由于在消费者中调用了 ExecuteAsync 方法,如果我们在它发出信号(或超时)之前不放一些东西来阻止它,这个测试方法就会失败。在上面的示例中,我们使用 AutoResetEvent 从回调中发出信号以继续并运行断言。

这是一个糟糕的方法,我们正在用尽所有资源来寻找替代方法。如果它不明显,这可能会在测试期间导致错误的失败和竞争条件。更不用说潜在的严重自动化测试时间了。

我们有哪些比目前更好的替代方案。

编辑这是我最初用于模拟 RestSharp 异步调用的来源。

How to test/mock RestSharp ExecuteAsync(...)

最佳答案

老实说,执行异步方法的复杂性是 MassTransit 3 的关键驱动因素之一。虽然它还没有准备好,但它使来自消费者的异步方法调用变得更好。

您在上面测试的是什么,因为您在 REST 客户端上调用 ExecuteAsync(),而不是在消费者中等待响应(使用 .Result 或 .Wait),HTTP 调用在消息消费者之后继续已经回来了。所以这可能是您问题的一部分。

在 MT3 中,此消费者将写为:

public async Task Consume(ConsumeContext<VerifyPhoneNumber> context)
{
try
{
var response = await _restClient
.ExecuteAsync<PhoneNumberVerificationResponse>(_request);
var phoneNumber = new PhoneNumber()
{
Number = response.PhoneNumber
};

await context.RespondAsync(new VerifyPhoneNumberSucceeded(context.Message)
{
PhoneNumber = _phoneNumber
});
}
catch (Exception exception)
{
context.Respond(new VerifyPhoneNumberFailed(context.Message)
{
PhoneNumber = context.Message.PhoneNumber,
Message = exception.Message
});
}
}

关于c# - 对使用异步调用的 MassTransit 消费者进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28723746/

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