faking API calls /w NSubstitute, for unit testing

岁酱吖の 提交于 2019-12-11 20:01:24

问题


I got a lot of function calls like the one below that I want to unit test but are unsure of how i should approach functions like these.. Do I just test it with the real URL and API calls?? but then it won't be a real unit test since I including things which I don't have control of... which leads me to the conclusion that I have to mock the RestClient out?? where I need to make a RestClient Foo(ApiUrl + ApiDirectory); which I can use NSubtitute on, is it the right way??

Would you guys approach it the same way? or is there a smart way do this unit test?

// ReSharper disable once InconsistentNaming
public IRestResponse TCAPIconnection( Method b, long c = 0, object d = null)
{
    var client = c == 0 ? new RestClient(ApiUrl + ApiDirectory) : new RestClient(ApiUrl + ApiDirectory + c);
    var request = new RestRequest(b);
    request.AddHeader("Authorization", Token);
    if (d != null)
    {
        request.AddJsonBody(d);
    }
    var response = client.Execute(request);
    return response;
}

回答1:


Your provided approach is not going to fly on a greater in size system as well as you actually alter your original code for testing purposes.

Mocking frameworks are generally used for unit-testing. Unit test in itself is just a small fraction of functionality, a single method. It most definitely do not involve services.

What you should be going for is abstractions upon which you can simply mock an interface which your services use.

Lets consider a short example. You have a IBluetoothService which is being injected into BluetoothManager class. The interface would expose few methods which on the test mode will be mocked.

public interface IBluetoothService
{
    object GetData();
    bool SendData(object request);
}

public class BluetoothAPI : IBluetoothService
{
    public object GetData()
    {
        // API logic to get data.
        return new object();
    }

    public bool SendData(object request)
    {
        // API logic to send data.
        return false;
    }
}

In your Logger class constructor you should inject IBluetoothService.

public class Logger
{
    private readonly IBluetoothService _bluetoothService;
    public Logger(IBluetoothService bluetoothService)
    {
        _bluetoothService = bluetoothService;
    }

    public void LogData(string textToLog)
    {
        if (!_bluetoothService.SendData(textToLog))
            throw new ArgumentException("Could not log data");
    }
}

So since you got this abstraction level going in your application you effectively start testing it.

public void SmokeTest()
{
    var substitute = Substitute.For<IBluetoothService>();
    substitute.GetData().Returns(1);
    // Swap true with false and test will fail.
    substitute.SendData(Arg.Any<object>()).Returns(true);
    var sut = new Logger(substitute);
    try
    {
        sut.LogData("Some data to log");
    }
    catch (ArgumentException ex)
    {
        Assert.Fail("Mocked API call returned wrong value.");
    }
}

NSubstitute is a powerful tool which allows you to test everything if you have the correct architecture in you application. To achieve a testable code you need little to nothing, just inject interface. This does not only allow you to have a testable but also more maintainable approach in software development.



来源:https://stackoverflow.com/questions/37193387/faking-api-calls-w-nsubstitute-for-unit-testing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!