everyone.
I have been trying write mock test to my IElasticClient calls, but I have problem with a error about convert. Convert IGetResponse to GetResponse.
My method of ElasicClient:
public class GetClientByIdQueryHandler : IQueryHandler<GetClientByIdQuery, Client>
{
private readonly IElasticClient _elasticClient;
private readonly IReadModel _readModel;
public GetProposalByIdQueryHandler(IElasticClient elasticClient, IReadModel readModel)
{
...
}
public async Task<Client> ExecuteQueryAsync(GetClientByIdQuery query, CancellationToken cancellationToken)
{
var readModelDescription = _readModel.GetReadModelDescription<ClientReadModel>();
var indexName = readModelDescription.IndexName.Value;
var getResponse = await _elasticClient
.GetAsync<ClientReadModel>(query.Id.Value, d => d.Index(indexName).RequestConfiguration(c => c.AllowedStatusCodes((int)HttpStatusCode.NotFound)), cancellationToken)
.ConfigureAwait(false);
return getResponse.Source;
}
}
My Mock test:
private const string _indexName = "client-document";
private ClientReadModel GetClientReadModel()
{
var response = JsonConvert.DeserializeObject<ClientReadModel>("...string json...");
return response;
}
[Fact]
public async Task GetClientByIdQueryHandler()
{
// Arrange
var mockElasticClient = new Mock<IElasticClient>();
var mockResponse = new Mock<IGetResponse<ClientReadModel>>();
mockResponse.SetupGet(r => r.Source).Returns(GetClientReadModel());
mockElasticClient
.Setup(x => x.GetAsync(
"id-d862975d-06ea-4f50-b7d3-d2b19413cb4c",
It.IsAny<Func<GetDescriptor<ClientReadModel>, IGetRequest>>(),
It.IsAny<CancellationToken>()))
.Returns(mockResponse.Object); // <== error here
...
...
}
Almost alright, but it returns a error on the line "Returns(mockResponse.Object);":
cannot convert from 'Nest.IGetResponse' to 'Nest.GetResponse
Someone have idea about resolve this problem?
Thanks!
Related
We have some external service method to call from our code, looks. like
AssignOrderReserveCommandResponseDto response = await _supplyReservesClient.AssignOrderReserve(
masterReserveId,
inboundReserveId,
deliveryDate,
orderInfos,
cancellationToken)
Mock for this method looks like:
public static readonly ISupplyReservesClient SupplyReservesClient = Substitute.For<ISupplyReservesClient>();
public static AssignOrderReserveCommandResponseDto assignOrderReserveCommandResponse;
static SupplyReservesClientMock()
{
SupplyReservesClient
.AssignOrderReserve(Arg.Any<Guid>(), Arg.Any<Guid>(),
Arg.Any<DateTimeOffset>(), Arg.Any<IReadOnlyCollection<AssignOrderInfo>>(),
Arg.Any<CancellationToken>())
.Returns(_ => assignOrderReserveCommandResponse);
}
public static void SetAssignOrderReserveCommandResponseDto(long bidId, long otherBidId)
{
Fixture fixture = new Fixture();
assignOrderReserveCommandResponse = fixture.Build<AssignOrderReserveCommandResponseDto>()
.With(x => x.OrderInfos, new List<AssignOrderReserveCommandResponseDto.OrderInfo>()
{
new(bidId, "1", DateTime.UtcNow.AddDays(3)),
new(otherBidId, "1", DateTime.UtcNow.AddDays(3))
})
.With(x => x.InboundReserveId, fixture.Create<Guid>())
.Create();
}
Mock doesn't work and method returns null when I use debug for my test or just run test
Method for mock:
public async Task<AssignOrderReserveCommandResponseDto> AssignOrderReserve(
Guid? masterReserveId,
Guid? inboundReserveId,
DateTimeOffset deliveryDate,
IReadOnlyCollection<AssignOrderInfo> orderInfos,
CancellationToken cancellationToken)
{
AssignOrderReserveCommand command = AssignOrderReserveConverter
.Convert(masterReserveId, inboundReserveId, deliveryDate, orderInfos);
AssignOrderReserveCommandResponse response = await _supplyReservesClient
.AssignOrderReserveAsync(command, cancellationToken: cancellationToken);
return AssignOrderReserveConverter.Convert(response);
}
i am new to integration tests. I have an xUnit project in my solution which contains one test only.
Here's the definition of my test:
[Fact]
public async Task ShouldCreateUser()
{
// Arrange
var createUserRequest = new CreateUserRequest
{
Login = "testowyLogin",
Password = "testoweHaslo",
FirstName = "testoweImie",
LastName = "testoweNazwisko",
MailAddress = "test#test.pl"
};
var serializedCreateUserRequest = SerializeObject(createUserRequest);
// Act
var response = await HttpClient.PostAsync(ApiRoutes.CreateUserAsyncRoute,
serializedCreateUserRequest);
// Assert
response
.StatusCode
.Should()
.Be(HttpStatusCode.OK);
}
And the BaseIntegrationTest class definition:
public abstract class BaseIntegrationTest
{
private const string TestDatabaseName = "TestDatabase";
protected BaseIntegrationTest()
{
var appFactory = new WebApplicationFactory<Startup>()
.WithWebHostBuilder(builder =>
{
builder.ConfigureServices(services =>
{
RemoveDatabaseContextFromServicesCollectionIfFound<EventStoreContext>(services);
RemoveDatabaseContextFromServicesCollectionIfFound<GrantContext>(services);
services
.AddDbContext<EventStoreContext>(options =>
options.UseInMemoryDatabase(TestDatabaseName))
.AddDbContext<GrantContext>(options =>
options.UseInMemoryDatabase(TestDatabaseName));
});
});
HttpClient = appFactory.CreateClient();
}
protected HttpClient HttpClient { get; }
protected static StringContent SerializeObject(object #object) =>
new StringContent(
JsonConvert.SerializeObject(#object),
Encoding.UTF8,
"application/json");
private static void RemoveDatabaseContextFromServicesCollectionIfFound<T>(IServiceCollection services)
where T : DbContext
{
var descriptor = services.SingleOrDefault(service =>
service.ServiceType == typeof(DbContextOptions<T>));
if (!(descriptor is null))
{
services
.Remove(descriptor);
}
}
}
When i run tests, it takes few seconds, and the test ends successfully. The problem is that Resharper Test Runner still runs, although i've already have collected results. what am i doing wrong here? Do i have to somehow dispose the HttpClient, after performing all tests? If so, how to achieve that? Thanks for any help.
It looks like you're actually booting the application inside the test rather than using the testhost (https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-3.1)
public class BasicTests
: IClassFixture<WebApplicationFactory<RazorPagesProject.Startup>>
{
private readonly WebApplicationFactory<RazorPagesProject.Startup> _factory;
public BasicTests(WebApplicationFactory<RazorPagesProject.Startup> factory)
{
_factory = factory;
}
[Theory]
[InlineData("/")]
[InlineData("/Index")]
[InlineData("/About")]
[InlineData("/Privacy")]
[InlineData("/Contact")]
public async Task Get_EndpointsReturnSuccessAndCorrectContentType(string url)
{
// Arrange
var client = _factory.CreateClient();
// Act
var response = await client.GetAsync(url);
// Assert
response.EnsureSuccessStatusCode(); // Status Code 200-299
Assert.Equal("text/html; charset=utf-8",
response.Content.Headers.ContentType.ToString());
}
}
Notice the IClassFixture stuff.
I am trying to write an unit test at the moment and i am having difficult with the mocking the RestSharp. The test i am trying to write is for the GetAll method.
This is the code that i am trying to test.
public class Client: IClient
{
public IRestClient RestClient { get; set; }
public IOptions<ClientSettings>Settings { get; set; }
public Client(IOptions<ClientSettings>options)
{
Settings = options;
RestClient = new RestClient(options.Value.BaseUrl);
}
public async Task<List<EventDTO>> GetAll()
{
var allEvents = await RetrieveAllEvents();
var data = TransformData(allEvents);
return data;
}
private static List<EventDTO> TransformData(IEnumerable<Event> allEvents)
{
var data = allEvents.SelectMany(con =>
con.Geometries.Select(geo =>
new EventDTO
{
Title = con.Title,
Id = con.Sources.FirstOrDefault()?.Id,
CategoriesTitle = con.Categories.FirstOrDefault()?.Title,
Closed = con.Closed,
DateTime = geo.Date
})
).ToList();
return data;
}
private async Task<IEnumerable<Event>> RetrieveAllEvents()
{
var openEvents = await RetrieveEvent(Settings.Value.GetAllOpen);
var closedEvents = await RetrieveEvent(Settings.Value.GetAllClosed);
var allEvents = openEvents.Events.Concat(closedEvents.Events);
return allEvents;
}
private async Task<RootObject> RetrieveEvent(string request)
{
var responseData = new RestRequest(request, Method.GET);
var content = await RestClient.GetAsync<RootObject>(responseData);
return content;
}
}
When the code gets to this line, it just stops working. I tried putting in a try and catch around it see what the error is but it just blows the stack.
var data = await RestClient.GetAsync<RootObject>(responseData);
I saw an example online and i tried mocking the RestSharp
restClient.Setup(c => c.ExecuteAsync<EventDTO>(
Moq.It.IsAny<IRestRequest>(),
Moq.It.IsAny<Action<IRestResponse<EventDTO>, RestRequestAsyncHandle>>()))
.Callback<IRestRequest, Action<IRestResponse<EventDTO>, RestRequestAsyncHandle>>((request, callback) =>
{
var responseMock = new Mock<IRestResponse<EventDTO>>();
responseMock.Setup(r => r.Data).Returns(new EventDTO() { });
callback(responseMock.Object, null);
});
I'm using FluentValidation to validate request. If the validation fails UseCaseHandler should not be invoked. Within the UseCaseHandler I'm usign IRepository, and this is checked to see if the UseCaseHandler gets invoked.
The Request validator
public class MyValidator: AbstractValidator<Request>
{
public MyValidator()
{
RuleFor(rq=> rq)
.Cascade(CascadeMode.Continue);
RuleFor(rq=> rq)
.Must(property => property.id != default(Guid))
.WithMessage(message => $"invalid id.")
.WithName(member => nameof(member.Id));
}
}
This is the test
[Fact]
public async Task Test()
{
Mock<IUnitOfWork> uowMock = new Mock<IUnitOfWork>();
Mock<IRepository> repositoryMock = new Mock<IRepository>(MockBehavior.Strict);
Mock<IValidator<Request>> validatorMock = new Mock<IValidator<Request>>(MockBehavior.Strict);
var request = new Request
{
Id = Guid.NewGuid()
};
validatorMock
.Setup(validator => validator.Validate(request))
.Returns(new ValidationResult());
repositoryMock
.Setup(repo => repo.SaveAsync(It.IsAny<object>()))
.Returns(Task.CompletedTask);
var sut = new UseCase(uowMock.Object, repositoryMock.Object, validatorMock.Object);
Func<Task> act = () => sut.UseCaseHandler(request);
await act.Should().NotThrowAsync();
repositoryMock.Verify(repo => repo.SaveAsync(It.IsAny<object>()), Times.Once);
}
I'm looking to write a test that will check the flow.
If the validation fails the test should fail and SaveAsync should not be called.
If the validation succeeds that the test should succeed also and SaveAsync should be called one time.
What is the way to write a test ?
UPDATE
This is the use case class definition.
UseCaseHandlerProxy is a base abstract class which acts as a proxy
public class UseCase : UseCaseHandlerProxy<Request, Response>
{
private readonly IRepository _repository;
public UseCase(IUnitOfWork unitOfWork, IRepository repository, IValidator<Request> validator)
: base(unitOfWork, validator)
{
_repository = repository
}
public override async Task<Response> UseCaseHandler(Request request)
{
Order order = new Order();
order.Create();
await _repository.SaveAsync(order);
return new Response(order.Id);
}
}
This is the Request class definition
class Request
{
public Guid Id { get; set; }
}
Te response only returns the same Id
Proxy class
public abstract class UseCaseHandlerProxy<TRequest, TResponse> : IUseCaseHandler<TRequest, TResponse>
where TRequest : IRequest
where TResponse : Response
{
private IValidator<TRequest> Validator { get; }
protected internal IUnitOfWork UnitOfWork { get; }
public UseCaseHandlerProxy(IUnitOfWork unitOfWork, IValidator<TRequest> validator)
{
Validator = validator;
UnitOfWork = unitOfWork;
}
async Task<TResponse> IUseCaseHandler<TRequest, TResponse>.HandleAsync(TRequest request)
{
ValidationResult validationResult = await Validator.ValidateAsync(request);
TResponse response;
if (!validationResult.IsValid)
{
response = (TResponse)System.Activator.CreateInstance(typeof(TResponse));
validationResult.Errors.ToList().ForEach(error => response.AddError(error.PropertyName, error.ErrorMessage));
return response;
}
response = await UseCaseHandler(request);
return response;
}
public abstract Task<TResponse> UseCaseHandler(TRequest request);
}
Given the flow you want to test I would say that you are invoking the wrong member.
Cast the sut to IUseCaseHandler<TRequest, TResponse> to get access to HandleAsync which is what does the desired flow.
For example the following verifies that if no validation error that repository invokes save.
[Fact]
public async Task UseCase_Should_Save() {
//Arrange
Mock<IUnitOfWork> uowMock = new Mock<IUnitOfWork>();
Mock<IRepository> repositoryMock = new Mock<IRepository>(MockBehavior.Strict);
Mock<IValidator<Request>> validatorMock = new Mock<IValidator<Request>>(MockBehavior.Strict);
var request = new Request {
Id = Guid.NewGuid()
};
validatorMock
.Setup(validator => validator.ValidateAsync(request, It.IsAny<CancellationToken>()))
.ReturnsAsync(new ValidationResult());
repositoryMock
.Setup(repo => repo.SaveAsync(It.IsAny<object>()))
.Returns(Task.FromResult((object)null));
var sut = new UseCase(uowMock.Object, repositoryMock.Object, validatorMock.Object) as IUseCaseHandler<Request, Response>;
//Act
Func<Task> act = () => sut.HandleAsync(request);
//Assert
await act.Should().NotThrowAsync();
repositoryMock.Verify(repo => repo.SaveAsync(It.IsAny<object>()), Times.Once);
}
The following verifies that if there are errors, then the repository does not save
[Fact]
public async Task UseCase_Should_Not_Save() {
//Arrange
var uowMock = new Mock<IUnitOfWork>();
var repositoryMock = Mock.Of<IRepository>();
var validatorMock = new Mock<IValidator<Request>>(MockBehavior.Strict);
var request = new Request {
Id = Guid.NewGuid()
};
var result = new ValidationResult();
result.Errors.Add(new ValidationFailure("SomeProperty", "SomeError"));
validatorMock
.Setup(validator => validator.ValidateAsync(request, It.IsAny<CancellationToken>()))
.ReturnsAsync(result);
var sut = new UseCase(uowMock.Object, repositoryMock, validatorMock.Object) as IUseCaseHandler<Request, Response>;
//Act
Func<Task> act = () => sut.HandleAsync(request);
//Assert
await act.Should().NotThrowAsync();
Mock.Get(repositoryMock).Verify(repo => repo.SaveAsync(It.IsAny<object>()), Times.Never);
}
I am having trouble setting up a unit test where I need to Moq the HttpClient. In my code I have a decorator for the HttpClient which follows an interface.
public class WHttpClient: IWHttpClient{
HttpClient _client = new HttpClient();
...
public async Task<HttpReponseMessage> PostAsJsonAsync<T>(string url, T content)
{
//Do Something
return await _client.PostAsJsonAsync(url, content);
}
...
}
public interface IWHttpClient{
HttpRequestHeaders DefaultRequestHeaders {get;}
Task<HttpResponseMessage> PostAsXmlAsync<T>(string url, T content);
Task<HttpResponseMessage> PostAsJsonAsync<T>(string url, T content);
Task<HttpResponseMessage> PostAsync<T>(string url, T content);
Task<HttpResponseMessage> GetAsync(string url);
Task<T> GetAsync<T>(string url);
Task<T> ReadAsAsync<T>(HttpResponseMessage response);
T Read<T>(HttpResponseMessage response);
}
[TestClass]
public class UnitTest1
{
private class WorkClass
{
private IWHttpClient _client;
public WorkClass(IWHttpClient client)
{
_client = client;
}
public void DoWork()
{
var url = "DUMMY";
var content = new ObjectToSerialize();
Task.Run(() => _client.PostAsJsonAsync(url, content));
}
}
public class ObjectToSerialize
{
}
[TestMethod]
public void TestMethod1()
{
Mock<IWHttpClient> _webClientMock = new Mock<IWHttpClient>(MockBehavior.Strict);
var url = "DUMMY";
var content = new ObjectToSerialize();
_webClientMock.Setup(x => x.PostAsJsonAsync(url, It.IsAny<ObjectToSerialize>())).Returns(Task.FromResult(new HttpResponseMessage(System.Net.HttpStatusCode.OK)));
var myClassToTest = new WorkClass(_webClientMock.Object);
myClassToTest.DoWork();
}
}
It successfully builds, but when I run the test, it gives me the exception:
System.MissingMethodException: Method not found: 'System.Threading.Tasks.Task'1 SomeNamespace.IWHttpClient.PostAsJsonAsync(System.String, !!0)'.
I've spent hours trying to figure out why I get this exception when I run the test. I have performed a clean and rebuild of my solution and yet it still appears as well as replacing the inputs in the mocksetup with:
(It.IsAny<string>(), It.IsAny<object>())
Does anyone have an idea what's wrong?
Results from running:
The following minimal example was just to try and reproduce your problem as well as demonstrate how to exercise tests like this.
[TestClass]
public class MyTestClass {
private class WorkClass {
private IWHttpClient _client;
public WorkClass(IWHttpClient client) {
_client = client;
}
public async Task DoWork() {
var url = "DUMMY";
var content = new ObjectToSerialize();
var response = await _client.PostAsJsonAsync(url, content);
}
}
public class ObjectToSerialize {
}
[TestMethod]
public async Task MyTestMethod() {
//Arrange
var expectedResponse = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
var _webClientMock = new Mock<IWHttpClient>(MockBehavior.Strict);
_webClientMock
.Setup(_ => _.PostAsJsonAsync(It.IsAny<string>(), It.IsAny<ObjectToSerialize>()))
.ReturnsAsync(expectedResponse)
.Verifiable();
var myClassToTest = new WorkClass(_webClientMock.Object);
//Act
await myClassToTest.DoWork();
//Assert
_webClientMock.Verify();
}
}
When exercised the test behaved as expected and passed. Even when the setup was changed to
.Setup(_ => _.PostAsJsonAsync(It.IsAny<string>(), It.IsAny<object>()))
Review and compare to your current test to help identify where possible mistakes may have been made.