如何使用模拟转换为Xunit

时间:2019-03-19 11:07:18

标签: xamarin.forms mocking xunit

服务类中有这两种方法

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();
    }
}

我需要将此代码添加到Xunit.cs中。怎么做?

我已经实现了这一点,但我不知道如何进行。

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()
{


}

这是我试图做的。如何将服务中的这两种方法转换为可测试的?

1 个答案:

答案 0 :(得分:0)

您确实嘲笑了一下。被模拟的不是被测组件,而是其依赖项。进行单元测试时,您想单独测试一个单元。如果您对PatientListPageViewModel进行了单元测试,那么您的模拟案例是正确的,但是由于您的测试类名为PatientServiceTests,所以我认为您确实想测试PatientService。如果您想测试前者,则完全可以模拟IPatientService,但是在测试PatientService时,IRestClientIAppSettings应该被模拟

public PatientServiceTests()
{
    _restClientMock = new Mock<IRestClient>();
    _appSettingsMock = new Mock<IAppSettings>();

    _patientService = new PatientService(_restClientMock.Object, _appSettingsMock.Object);         
}

您的测试可能类似于

[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
}

如果要测试URL的格式是否正确,可以使用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);
}

在这种情况下,我们正在设置IRestClient,因为否则它将返回nullawait null会导致您的测试失败。调用GetPatients之后,我们将使用Verify来验证是否已使用正确的参数调用了GetAsync。如果尚未调用,则会抛出Verify并且测试将失败。 Times.Once意味着GetAsync应该被调用过一次,并且只能被调用一次。

附带说明:Viewmodels仅在用户界面的上下文中具有含义。服务应该是独立的,因此不会像您那样返回视图模型,而是返回POCO(或域模型)。在这种情况下,您的服务界面应为

public interface IPatientService 
{
    public async Task<IList<Patient>> GetPatients(int wardId);
    // ...
}