问题
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