How to convert to Xunit using mocking - xamarin.forms

I have these two methods in my service class
public class PatientService : IPatientService
{
private readonly IRestClient _restClient;
private readonly IAppSettings _appSettings;
public PatientService(IRestClient restClient, IAppSettings appSettings)
{
_restClient = restClient;
_appSettings = appSettings;
}
public async Task<IList<PatientViewModel>> GetPatients(int wardId)
{
var url = _appSettings.Server + _appSettings.PatientServiceEndPoint + wardId;
var token = _appSettings.Token;
return GetPatientList(await _restClient.GetAsync<List<PatientInfo>>(url, token));
}
public IList<PatientViewModel> GetPatientList(IList<PatientInfo> patientInfoList)
{
return patientInfoList.Select(p => new PatientViewModel(p)).ToList();
}
}
I need to add this code to my Xunit.cs. How to do it?
I've implemented this and I do not know how to proceed.
private readonly PatientListPageViewModel _patientListPageViewModel;
private readonly Mock<IPatientService> _patient;
public PatientServiceTests()
{
_patient = new Mock<IPatientService>();
_patientListPageViewModel = new PatientListPageViewModel(_patient.Object);
}
[Fact]
public void GetListByWard_PassingWardId_GetPatientsCountAccordingToWardId()
{
}
This is what I tried to do. How to convert those two methods in service to be testable?

You did get mocking a bit wrong. It is not the component under test that is mocked, but its dependencies. When unit-testing you'd like to test a unit in isolation. Your case of mocking would be kind of correct if you unit-tested the PatientListPageViewModel, but since your test class is named PatientServiceTests I assume that you really wanted to test PatientService. If you wanted to test the former, you would be quite right to mock IPatientService, but when testing PatientService, IRestClient and IAppSettings shall be mocked
public PatientServiceTests()
{
_restClientMock = new Mock<IRestClient>();
_appSettingsMock = new Mock<IAppSettings>();
_patientService = new PatientService(_restClientMock.Object, _appSettingsMock.Object);
}
And your test could be something like
[Fact]
public async Task ReturnsCorrectPatientList() // async supported as of xUnit 1.9
{
// set up the mock
_restClientMock.SetUp(restClient => restClient.GetAsync<List<Patient>>(It.IsAny<string>(), It.IsAny<string>())
.Returns(() => Task.FromResult(/* what patients it shall return */));
var result = await _patientService.GetPatients(0);
// compare whether the returned result matches your expectations
}
If you wanted to test whether the URL is formed correctly, you could use Verify
[Theory]
[InlineData("SERVER", "ENDPOINT", 12, "1234", "SERVERENDPOINT12")]
[InlineData("https://localhost:65000", "/patients/", 5, https://localhost:65000/patients/5")]
public void TestWhetherCorrectUrlIsCalled(string server, string endpoint, int wardId, string token, string expectedUrl)
{
_appSettingsMock.SetupGet(appSettings => appSettings.Server).Returns(server);
_appSettingsMock.SetupGet(appSettings => appSettings.PatientServiceEndPoint).Returns(endpoint);
_appSettingsMock.SetupGet(appSettings => appSettings.Token).Returns(token);
_restClientMock.SetUp(restClient => restClient.GetAsync<List<Patient>>(It.IsAny<string>(), It.IsAny<string>())
.Returns(() => Task.FromResult(new List<Patient>()));
// we do not need the result
await _patientService.GetPatients(wardId);
_restClientMock.Verify(restClient => restClient.GetAsync<List<Patient>>(exptectedUrl, token), Times.Once);
}
We are setting up the IRestClient in this case, since it would return null otherwise. And await null would cause your test to fail. After GetPatients has been called we are using Verify to verify that GetAsync has been called with the correct parameters. If it has not been called, Verify will throw and your test will fail. Times.Once means, that GetAsync shall have been called once and only once.
On a side note: Viewmodels shall have a meaning in the context of your user interface only. Services shall be independent and hence not return viewmodels, as you did, but POCOs (or maybe domain models). In this case the interface of your service should be
public interface IPatientService
{
public async Task<IList<Patient>> GetPatients(int wardId);
// ...
}

Related

Mock IRequestClient<> during Integration Testing using MassTransit

I'm trying to do integration testing against a MediatR Command whose handler depends on an IRequestClient injected into its constructor.
public class SayHelloCommand : IRequest<string>
{
}
public class SayHelloCommandHandler : IRequestHandler<SayHelloCommand, string>
{
private readonly IRequestClient<IGetProfileMessageResult> _profileClient;
public SayHelloCommandHandler(IRequestClient<IGetProfileMessageResult> profileClient)
{
_profileClient = profileClient;
}
public async Task<string> Handle(SayHelloCommand request, CancellationToken cancellationToken)
{
var profile = (await _profileClient.GetResponse<IGetProfileMessageResult>(new {ProfileId = 1})).Message;
return $"Hello {profile.FirstName}";
}
}
I've setup my test suite to use the InMemoryMassTransit but whenever I run my test it times out when it reaches the call using the IRequestClient<>. I've also tried to moq the IRequestClient to return a default response like this -
[Test]
public async Task ShouldSayHello()
{
var mockRequestClient = new Mock<IRequestClient<IGetProfileMessageResult>>();
mockRequestClient.Setup(x => x.GetResponse<IGetProfileMessageResult>(It.IsAny<Object>(), default, default)
.Result.Message).Returns(new GetProfileMessageResult
{
FirstName = "John"
});
serviceCollection.Add(new ServiceDescriptor(typeof(IRequestClient<IGetProfileMessageResult>), mockRequestClient.Object));
var result = await SendAsync(command);
result.Status.Should().BeFalse();
result.Message.Should().Contain("John");
}
but this still times out.
Is there a way I can set up the InMemoryMassTransit to return a default response when the requestclient is called?
You could use the in-memory test harness to setup a simple consumer that would respond to the request, instead of trying to mock IRequestClient. Though you should be able to mock it if you want, I just don’t know the syntax to properly configure your mock framework.
There are many samples using the test harness available, as well as all of the MassTransit unit tests.

How to pass my DbContext object for testing using xunit and moq

Below mentioned is the test function that checks if details exist for the particular transactionId.
[Fact]
public async Task GetAllBlobDetails_Test()
{
_serviceScopeFactory.Setup(x => x.CreateScope().ServiceProvider.GetRequiredService<MriDbContext>()).Returns(_context);
BlobStatusEntity blobStatusEntity = await _bspRepository.GetBlobDetails("123");
Assert.NotNull(blobStatusEntity)
}
where _serviceScopeFactory is
Mock<IServiceScopeFactory> _serviceScopeFactory = new Mock<IServiceScopeFactory>();
(Microsoft.Extensions.DependencyInjection)
In the above function it calls _bspRepository.GetBlobDetails for particular transactionId ("123")
So here is the definition for GetBlobDetails
public async Task<BlobStatusEntity> GetBlobDetails(string transactionId)
{
if (String.IsNullOrEmpty(transactionId))
{
throw new ArgumentNullException(nameof(transactionId));
}
MriDbContext mriDbcontext = _scopeFactory.CreateScope().ServiceProvider.GetRequiredService<MriDbContext>();
return await mriDbContext.BlobStatus.FirstOrDefaultAsync(ele => ele.TransactionId == transactionId);
}
where _scopeFactory is IServiceScopeFactory _scopeFactory which is injected from the constructor.
When I am running the above test function GetAllBlobDetails_Test, I am getting the following error like this.
Message:
System.NotSupportedException : Unsupported expression: ... => ....GetRequiredService<MriDbContext>()
Extension methods (here: ServiceProviderServiceExtensions.GetRequiredService) may not be used in setup / verification expressions.
I am new to moq and xunit.
Please help me to resolve this issue.
Thanks in advance
So the root cause here is that you can't mock an extension method in Moq
You're doing this here:
_serviceScopeFactory.Setup(x => x.CreateScope().ServiceProvider.GetRequiredService<MriDbContext>()).Returns(_context);
GetRequiredService<T> is an extension method that extends IServiceProvider which you can see here
Depending on what the specific case you're trying to test is (are you testing the context creation, or the actual write to the DB?), you should be able to re-write your test to avoid mocking the extension method and mocking the public instance methods being used instead. You could even mock the actual instance method on IServiceProvider if you really wanted to keep the existing structure.
Further discussion of this topic exists here. That question uses MSTest rather than XUnit, but your issue here is specific to Moq.
Here is the initialization part
private BspRepository _bspRepository;
private Mock<IServiceScopeFactory> _serviceScopeFactory;
private Mock<ILogger<BspRepository>> _logger;
private Mock<IMapper> _mapper;
private DbContextOptions<MriDbContext> _options;
private MriDbContext _context;
private Mock<IServiceProvider> _serviceProvider;
private Mock<IServiceScope> _serviceScope;
public BSPRepositoryTests()
{
_serviceScopeFactory = new Mock<IServiceScopeFactory>();
_logger = new Mock<ILogger<BspRepository>>();
_mapper = new Mock<IMapper>();
_serviceProvider = new Mock<IServiceProvider>();
_serviceScope = new Mock<IServiceScope>();
_options = SetupDBContext();
_context = new MriDbContext(_options);
_bspRepository = new BspRepository(_serviceScopeFactory.Object, _logger.Object, _mapper.Object);
SetupData();
SetupServices();
}
I resolved my error by mocking objects in this way
private void SetupServices()
{
_serviceProvider.Setup(x => x.GetService(typeof(MriDbContext))).Returns(_context);
_serviceScope.Setup(x => x.ServiceProvider).Returns(_serviceProvider.Object);
_serviceScopeFactory.Setup(x => x.CreateScope())
.Returns(_serviceScope.Object);
}

in API, create multiple controller constructor with one parameter

[Route("api/[controller]")]
public class DigitalDocumentController : Controller
{
private IDigitalDocumentService digitalDocumentService;
private IDatabaseInitializer databaseInitializer;
public DigitalDocumentController(IDigitalDocumentService digitalDocumentService)
{
this.digitalDocumentService = digitalDocumentService;
}
public DigitalDocumentController(IDatabaseInitializer databaseInitializer)
{
this.databaseInitializer = databaseInitializer;
}
i want two controller constructor in my project to Mock in xUnit Testing, but there was an error in my swagger interface {
"error": "Multiple constructors accepting all given argument types have been found in type 'i2ana.Web.Controllers.DigitalDocumentController'. There should only be one applicable constructor."
}
can anybody help me how i can do it ?
…
what i am try to do , is to test Uniquness of the Name Field in my database
My testing code:
[Fact]
public void AddNotUniqueName_ReturnsNotFoundObjectResult()
{
var digitalDocument = new DigitalDocument
{
Image = new byte[] { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 },
CreatedOn = DateTime.Today,
Id = 6,
Location = "temp",
Name = "Flower",
Tages = new List<Tag> { new Tag { Id = 1, Value = "Tag 1" }, new Tag { Id = 1, Value = "Tag 2" } }
};
// Arrange
var mockRepo = new Mock<IDatabaseInitializer>();
mockRepo.Setup(repo => repo.SeedAsync()).Returns(Task.FromResult(AddUniqueDigitalDocument(digitalDocument)));
var controller = new DigitalDocumentController(mockRepo.Object);
// Act
var result = controller.Add(digitalDocument);
// Assert
var viewResult = Assert.IsType<NotFoundObjectResult>(result);
var model = Assert.IsAssignableFrom<int>(viewResult.Value);
Assert.NotEqual(6, model);
}
the "AddUniqueDigitalDocument" returns 6 only to test that the new digitaldocumet is not the same id of my initialize data.
When using dependency injection, you should only have one constructor where all dependencies can be satisfied. Otherwise, how is the DI container to know which constructor to utilize? That's your issue here. Using the Microsoft.Extensions.DependencyInjection package, and since this is a controller you're injecting into, there's only one reasonable way to solve this: don't register one or the other of the services, IDigitalDocumentService or IDatatabaseInitializer. If only one is registered, the service collection will simply use the constructor it has a registered service for.
It's possible with a more featured DI container, you might be able to configure something to allow it choose the proper constructor. How to do that would be entirely dependent on the DI container you end up going with, though, so not much more can be said on the subject at this point. Just realize that the default container (Microsoft.Extensions.DependencyInjection) is intentionally simplistic, so if you needs are more complex, you should sub in a full DI container.
UPDATE
You should be doing integration testing with the test host and an in-memory database. The basic approach is:
public MyTests()
{
_server = new TestServer(new WebHostBuilder().UseStartup<TestStartup>());
_context = _server.Host.Services.GetRequiredService<MyContext>();
_client = _server.CreateClient();
}
In your app's Startup, create a virtual method:
public virtual void ConfigureDatabase(IServiceCollection services)
{
// normal database setup here, e.g.
services.AddDbContext<MyContext>(o =>
o.UseSqlServer(Configuration.GetConnectionString("Foo")));
}
Then, in ConfigureServices, replace your database setup with a call to this method.
Finally, in your test project, create a TestStartup class and override the ConfigureDatabase method:
public class TestStartup : Startup
{
public override void ConfigureDatabase(IServiceCollection services)
{
var databaseName = Guid.NewGuid().ToString();
services.AddDbContext<MyContext>(o =>
o.UseInMemoryDatabase(databaseName));
}
}
Now, in your tests you just make requests against the test client (which is just an HttpClient instance, so it works like any other HttpClient). You start by setting up your database with appropriate test data, and then ensure that the correct response is returned:
// Arrange
_context.Add(new DigitalDocument { Name = "Foo" });
await _context.SaveChanges();
// Act
// Submit a `DigitalDocument` with the same name via `_client`
// Assert
// Inspect the response body for some indication that it was considered invalid. Or you could simply assert that no new `DigitalDocument` was created by querying `_context` (or both)
This is admittedly a lot easier with an API, as with a web application, you're going to invariably need to do some HTML parsing. However, the docs and corresponding sample app help you with that.
Additionally, in actual practice, you'd want to use a test fixture to prevent having to bootstrap a test server for every test. Again, the docs have you covered there. One thing to note, though, is that once you switch to using a fixture, your database will then be persisted between tests. To segregate your test data, make sure that you call EnsureDeleted() on your context before each test. This can be easily done in the test class' constructor:
public class MyTests : IClassFixture<WebApplicationFactory<Startup>>
{
private readonly HttpClient _client;
private readonly MyContext _context;
public MyTests(WebApplicationFactory<Startup> factory)
{
factory = factory.WithWebHostBuilder(builder => builder.UseStartup<TestStartup>());
_client = factory.CreateClient();
_context = factory.Server.Host.Services.GetRequiredService<MyContext>();
_context.EnsureDeleted();
}
I don't even like this much bootstrapping code in my tests, though, so I usually inherit from a fixture class instead:
public class TestServerFixture : IClassFixture<WebApplicationFactory<Startup>>
{
protected readonly HttpClient _client;
protected readonly MyContext _context;
public TestServerFixture(WebApplicationFactory<Startup> factory)
{
factory = factory.WithWebHostBuilder(builder => builder.UseStartup<TestStartup>());
_client = factory.CreateClient();
_context = factory.Server.Host.Services.GetRequiredService<MyContext>();
_context.EnsureDeleted();
}
}
Then, for each test class:
public class MyTests : TestServerFixture
{
public MyTests(WebApplicationFactory<Startup> factory)
: base(factory)
{
}
This may seem like a lot, but most of it is one-time setup. Then, your tests will be much more accurate, more robust, and even easier in many ways.

How to mock method with parameters

I am still learning Moq and am writing a unit test using Moq:
[TestMethod]
public void ProcessFileRowQueue()
{
var mock = new Mock<EdiEntityManager>();
mock.Setup(s => s.GetFileRowEntitiesToProcess()).Returns(GetMockFileRowEntities);
var controller = new EdiController("LOCAL", mock.Object);
controller.ProcessFileRowQueue();
}
This works.
Now, I want to ensure that the ensure ProcessFileRowQueue() actually did it's job. There is a method on EdiManager that I would like to mock so I can intercept the parameters and inspect them and ensure they are correct.
public virtual void SaveNewEdiDocument(EdiDocument ediDocument, Translation translation)...
However, I don't see how to mock a method with parameters.
This is what I thought it would be:
mock.Setup(s => s.SaveNewEdiDocument(It.IsAny<EdiDocument>(), It.IsAny<Translation>()).Returns(ValidateResults));
How do I write this, or is there a different way I should be verifying the results?
I found the Callback method:
[TestMethod]
public void ProcessFileRowQueue()
{
var mock = new Mock<EdiEntityManager>();
mock.Setup(s => s.GetFileRowEntitiesToProcess()).Returns(GetMockFileRowEntities);
mock.Setup(s => s.SaveNewEdiDocument(It.IsAny<EdiDocument>(), It.IsAny<Translation>()))
.Callback<EdiDocument, Translation>(VerifyResult);
var controller = new EdiController("LOCAL", mock.Object);
controller.ProcessFileRowQueue();
}
public void VerifyResult(EdiDocument ediDocument, Translation translation)
{
}

Moq: setting up for a method which returns no value

I'm trying to mock out a call to a repository. I can successfully do so when a repository call returns a value by using Setup().Returns:
mock.Setup(m => m.Get(param)).Returns(new CustomObject());
However, when I try to do the same sort of Setup for repository calls which return no values, Moq throws an exception and tells me this method was never called i.e.Expected invocation on the mock exactly 1 times, but was 0 times
Precisely, I'm doing this:
mock.Setup(m => m.UpdateRepository(param1)); // UpdateRepository returns no value
service.DoUpdate(param1);
mock.Verify(m => m.UpdateRepository(param1), Times.Exactly(1));
Note: DoUpdate method only calls repository.UpdateRepository(param1);
Am I not using Moq setup correctly in this instance? Is there a different way to Setup methods which return no value?
Thanks in advance!
You don't need to setup the call to UpdateRepository. Just verify it.
Given these types:
public interface IRepository
{
void UpdateRepository(string value);
}
public class Service
{
public Service(IRepository repository)
{
_repository = repository;
}
public void DoUpdate(string value)
{
_repository.UpdateRepository(value);
}
private IRepository _repository;
}
Your test method could be as follows:
const string param1 = "whatever";
var repoMock = new Mock<IRepository>();
var sut = new Service(repoMock.Object);
sut.DoUpdate(param1);
repoMock.Verify(x => x.UpdateRepository(param1), Times.Once());
Try using Verifiable:
mock.Setup(m => m.UpdateRepository(param1)).Verifiable();

Resources