I'm working on creating unit tests using moq and I'm having trouble figuring out how to apply this framework to a portion of my program that deals with using an HttpClient. There's various resources I found that demonstrate how to mock an HttpClient response directly but the way my application makes use of HttpClient is slightly different with the utilization of Threads.
The test's skeleton:
public class MyTestClass
{
public void myTest()
{
ClassA classObj = new ClassA();
classObj.Start();
// I'd like to use moq somewhere here to mock the response that occurs in DoThreadStuff() below
}
}
The class under testing:
public class ClassA
{
private readonly Thread _myThread;
private HttpClient _client;
public ClassA()
{
// initialize some values
_myThread = new Thread(DoThreadStuff);
}
public void Start()
{
_myThread.Start(); // starts DoThreadStuff()
}
private void DoThreadStuff()
{
var newClient = getNewHttpClient(); // utility function returns a HttpClient
var response = newClient.GetAsync("/my/api/status/endpoint");
}
}
As you can see, when ClassA.Start() gets called, a new HttpClient gets created and used via GetAsync. What would the correct way to structure a test for this look like? Will I have to change the implementation of my existing classes to accommodate for Moq? Does anyone have experience with something very similar which I could take a look at?
Let's suppose that your ClassA looks like this:
public class ClassA
{
private readonly Thread _myThread;
public ClassA()
{
_myThread = new Thread(DoThreadStuff);
}
public void Start()
{
_myThread.Start();
}
private void DoThreadStuff()
{
var newClient = getNewHttpClient();
var response = newClient.GetAsync("https://httpstat.us//200").GetAwaiter().GetResult();
if(response.StatusCode == HttpStatusCode.OK)
Console.WriteLine("OK");
else if(response.StatusCode == HttpStatusCode.InternalServerError)
Console.WriteLine("Not good");
}
protected virtual HttpClient getNewHttpClient()
{
return new HttpClient();
}
}
For the sake of testability I've added some dummy code after the getNewHttpClient call
Please note that calling an async method in sync fashion (.GetAwaiter().GetResult()) is not really a good idea
I've also added the getNewHttpClient to your class as protected virtual to be able to overwrite it easily
Now let's create a helper method to be able to mock an HttpClient:
public static HttpClient SetupMockClient(HttpResponseMessage response)
{
var mockMessageHandler = new Mock<HttpMessageHandler>();
mockMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(response);
return new HttpClient(mockMessageHandler.Object);
}
Let's derive from the ClassA to override the getNewHttpClient method
internal class VerifiableClassA : ClassA
{
private HttpClient mockedHttpClient;
public VerifiableClassA(HttpClient mockedHttpClient)
{
this.mockedHttpClient = mockedHttpClient;
}
protected override HttpClient getNewHttpClient()
{
return this.mockedHttpClient;
}
}
Please note that you can do this with moq as well so you don't need to introduce a new class just for testing. But in that case the getNewHttpClient should be public.
Now you can perform unit testing like this:
var mockedClient = SetupMockClient(new HttpResponseMessage
{
StatusCode = HttpStatusCode.InternalServerError,
Content = new StringContent("Failure")
});
var sut = new VerifiableClassA(mockedClient);
sut.Start();
You should consider to use a Factory/Repository-Pattern. They make it easier to Test your methods because you can just inject mocks of objects like HttpClient. The answer Peter Csala suggested is pretty dirty because you create a class that has the single purpose to be used in a test.
Related
I have an old version of ASP.NET MVC app that doesn't have a Startup.cs. I wanted to implement a clean way to have an HttpClient that I would use for my API calls to third parties.
Here's what I've done so far based on some ideas/recommendations I've received for this question. The problem is that when I make the API call, it goes nowhere. I put it in a try catch but I'm not even getting an exception. The API provider tells me that they're not seeing the search parameter.
First, I created this HttpClientAccessor for lazy loading.
public static class HttpClientAccessor
{
public static Func<HttpClient> ValueFactory = () =>
{
var client = new HttpClient();
client.BaseAddress = new Uri("https://apiUrl.com");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.TryAddWithoutValidation("APIAccessToken", "token1");
client.DefaultRequestHeaders.TryAddWithoutValidation("UserToken", "token2");
return client;
};
private static Lazy<HttpClient> client = new Lazy<HttpClient>(ValueFactory);
public static HttpClient HttpClient
{
get { return client.Value; }
}
}
I then created an API client of my own so that I can have the API call functions in one place which looks like this:
public class MyApiClient
{
public async Task GetSomeData()
{
var client = HttpClientAccessor.HttpClient;
try
{
var result = await client.GetStringAsync("somedata/search?text=test");
var output = JObject.Parse(result);
}
catch(Exception e)
{
var error = e.Message;
}
}
}
Then in my ASP.NET Controller action, I do this:
public class MyController : Controller
{
private static readonly MyApiClient _apiClient = new MyApiClient ();
public ActionResult ApiTest()
{
var data = _apiClient.GetSomeData().Wait();
}
}
Any idea where my mistake is?
UPDATE:
This simple approach works fine:
public class MyController : Controller
{
private static readonly HttpClient _client = new HttpClient();
public ActionResult ApiTest()
{
_client.BaseAddress = new Uri("https://apiUrl.com");
_client.DefaultRequestHeaders.Accept.Clear();
_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
_client.DefaultRequestHeaders.TryAddWithoutValidation("APIAccessToken", "token1");
_client.DefaultRequestHeaders.TryAddWithoutValidation("UserToken", "token2");
var response = _client.GetStringAsync("somedata/search?text=test").Result;
}
}
As mentioned, dependency injection is not being utilized so technically there is no need for a composition root where these things would have been initialized.
If there is no need to actually initialize the client on start up you could consider using a Lazy singleton approach.
An example
public static class HttpClientAccessor {
public static Func<HttpClient> ValueFactory = () => {
var client = new HttpClient();
client.BaseAddress = new Uri("https://apiUrl.com");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.TryAddWithoutValidation("APIAccessToken", "token1");
client.DefaultRequestHeaders.TryAddWithoutValidation("UserToken", "token2");
return client;
};
private static Lazy<HttpClient> client = new Lazy<HttpClient>(ValueFactory);
public static HttpClient HttpClient {
get { return client.Value; }
}
}
The factory delegate of the Lazy<HttpClient> can be made more complex if additional settings are needed on the client.
And where ever the client is needed you call the service
var client = HttpClientAccessor.HttpClient;
var response = await client.GetStringAsync("{url}");
the client will be initialized on first use and you will get the same instance on subsequent calls for the instance.
As used in your controller, you are mixing async calls with blocking calls line .Wait() or .Result. This can lead to deadlocks and should be avoided.
public class MyController : Controller {
private static readonly MyApiClient _apiClient = new MyApiClient ();
public async Task<ActionResult> ApiTest() {
var data = await _apiClient.GetSomeData();
//...
}
}
Code should be async all the way through.
Reference Async/Await - Best Practices in Asynchronous Programming
The Application_Start() method is the right place. But I would have to ask: why you have to create the HttpClient instance when the "application starts"? In general, HttpClient is some "resource" and you can just create it when you want to use it. And also it's no need to set it as "Singleton". Just wrap it in the using block. (Maybe you want to make the API wrapper as Singleton?)
public class APICaller
{
//make the APICaller singleton in some way here
//...
// the api calling method:
public string CallAPI(string someParameter)
{
var response = "";
using (var client = new HttpClient())
{
//calling the API
}
return response;
}
}
The main issue is incorrect asynchronous code.
You are using Task.Wait() which alongside asynchronous MyApiClient.GetSomeData() causes a deadlock on ASP.NET request context. That is a very common issue, see An async/await example that causes a deadlock on StackOverflow. Code with Task.Result property call is working because HttpClient.GetStringAsync() probably takes preventative measures against deadlocks. See Task.ConfigureAwait() page on MSDN and Best practice to call ConfigureAwait for all server-side code discussion on StackOverflow.
There are multiple options to write a singleton using C#. See Implementing the Singleton Pattern in C# article by Jon Skeet for a detailed overview.
As you mentioned, you can just use a static class member on the controller. HttpClient only needs to be setup once; so do this in the static constructor of the controller. Also, make sure that you use async/await for async methods, especially with long running http requests. IOC and an abstraction layer would make sense depending on your needs.
using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace TestApi
{
public class MyController : Controller
{
private const string ApiUrlString = "https://apiUrl.com";
private static readonly Uri ApiUri = new Uri(ApiUrlString);
private static readonly HttpClient RestClient;
static MyController()
{
this.RestClient = new HttpClient{
BaseAddress = ApiUri
}
this.RestClient.DefaultRequestHeaders.Accept.Clear();
this.RestClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
RestClient.DefaultRequestHeaders.TryAddWithoutValidation("APIAccessToken", "token1");
RestClient.DefaultRequestHeaders.TryAddWithoutValidation("UserToken", "token2");
}
public async Task<IActionResult> ApiTest()
{
return this.Ok(await this.RestClient.GetStringAsync("somedata/search?text=test"));
}
}
}
Is it possible to create a class under test with FakeItEasy, where all dependencies that are declared in the constructor are initialized automatically with fakes?
Imagine the class:
public class Inserting
{
public Inserting(
ITransactionService transactionService,
ISharedData sharedData)
{
TransactionService = transactionService;
SharedData = sharedData;
}
public ITransactionService TransactionService { get; }
public ISharedData SharedData { get; }
public void Enter()
{
TransactionService.StartTransaction();
}
}
Then I am creating all fake-objects in the test setup and construct my class under test with those fakes:
public class InsertingTest
{
private Inserting _inserting;
private ISharedData _fakeSharedData;
private ITransactionService _fakeTransactionService;
[SetUp]
public void SetUp()
{
_fakeTransactionService = A.Fake<ITransactionService>();
_fakeSharedData = A.Fake<ISharedData>();
_inserting = new Inserting(_fakeTransactionService, _fakeSharedData);
}
[Test]
public void TestEnter()
{
// Arrange
// Act
_inserting.Enter();
// Assert
A.CallTo(() => _fakeTransactionService.StartTransaction().MustHaveHappened();
}
}
But I saw in the Java-world, that when using Mockito and Dagger 2, you can do something like this:
public class PhoneDialer {
private Activity activity;
private PhoneCallListener phoneCallListener;
#Inject
public PhoneDialer(Activity activity, PhoneCallListener phoneCallListener) {
this.activity = activity;
this.phoneCallListener = phoneCallListener;
}
}
public class PhoneDialerTest {
#Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
#Mock
PhoneCallListener phoneCallListener;
#Mock
Activity activity;
#InjectMocks
PhoneDialer dialer;
#Test
public void test_dialer() throws Exception {
// Arrange
// Act
dialer.callNumber("abc");
// Assert
Mockito.verify(phoneCallListener, times(1)).startCall();
}
}
and the mocked classes are initialized automatically with fakes. Is there an equivalent procedure or function in C# with FakeItEasy?
I think you want something like
Automatically inject fakes in test fixture with FakeItEasy. You use [Fake] to mark fakes to inject and [UnderTest] to mark the production type to test.
We really should put this into the documentation.
Alternatively,
AutoFixture has an AutoFixture.AutoFakeItEasy module,
there's Autofac FakeItEasy integration, and also
Ninject FakeItEasy integration
I saw 'Automatically inject fakes in text fixture with FakeItEasy' and my initial reaction was surprise that it differed from my preconception, mainly because it needs 'intrusive' changes that attribute the test code... but perhaps that is an overreaction.
The FakeAttribute and UnderTestAttribute do force what is potentially a good structural constraint on your test (and system) design...
[FWLIW, before googling this, I had imagined the following:
containerBuilder.RegisterAsFakeCallingBaseType<SystemUnderTest>();
You can do something like this with Autofac's registration sources.
using Autofac;
using Autofac.Core;
using Autofac.Core.Activators.Delegate;
using Autofac.Core.Lifetime;
using Autofac.Core.Registration;
using FakeItEasy;
using Xunit;
public interface IDependOnSomething { }
public class IImplementThat : IDependOnSomething { }
public class CanIResolveIt
{
public CanIResolveIt(IDependOnSomething it)
{
}
}
public class FakeRegistrationSourceTest
{
[Fact]
public void BasicTest()
{
var container = new ContainerBuilder();
container.RegisterTypes<IImplementThat>().As<IDependOnSomething>();
container.RegisterSource(new FakeRegistrationSource<CanIResolveIt>());
var c = container.Build();
var theFake = c.Resolve<CanIResolveIt>();
Assert.NotNull(theFake);
}
}
public class FakeRegistrationSource<T> : IRegistrationSource
where T : class
{
public bool IsAdapterForIndividualComponents => false;
public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
var swt = service as IServiceWithType;
if (swt == null || !typeof(T).IsAssignableFrom(swt.ServiceType)) // TODO: is this the right way around?
{
return Enumerable.Empty<IComponentRegistration>();
}
var registration = new ComponentRegistration(
Guid.NewGuid(),
new DelegateActivator(swt.ServiceType, (context, #params) =>
{
List<object> v = new List<object>();
foreach (ParameterInfo p in typeof(T).GetConstructors().Single().GetParameters())
{
v.Add(context.Resolve(p.ParameterType));
}
return A.Fake<T>(that => that.CallsBaseMethods().WithArgumentsForConstructor(v));
}),
new CurrentScopeLifetime(),
InstanceSharing.None,
InstanceOwnership.OwnedByLifetimeScope,
new[] { service },
new Dictionary<string, object>());
return new IComponentRegistration[] { registration };
}
}
Main advantage of this approach is that it knows how to instantiate fake objects subclassing classes with constructor parameters, and inheriting their default behavior, when they have a single constructor (choosing intelligently from multiple constructors would be an obvious challenge that I'm not going to tackle...)
An obvious drawback is explicit registration every time you want something faked. AutoFake and so on offer ways to overcome that with faking of just about everything by default, which might well be what you want... and you can override it if not.]
I am using Moq to write a unit test. I have a DataManager object which calls WCF to fetch data. I inject this into my controller. however inside the controller the call to the Method in this DataManager is wrapped inside of a Task
System.Threading.Tasks.Task.Factory.StartNew<MyDataObject>(()=>
{
return DataManager.GetMyDataObject(userobj, recordid);
}
I have created a mock for the DataManager.GetMyDataObject with Moq
but whenever it is called from this statement inside of the controller method
it returns null. I have googled alot but most of the stuff out there are dealing with methods which have Task as the return signature.
The DataManager.GetMyDataObject is written as standard sync code.
I am using Moq v4.0.10827 and doubt I can upgrade.
I am trying many ways..Moq seems to expect the return to match the method signature
_mockDataManager = new Mock<_mockDataManager>();
_mockDataManager.Setup(m => m.GetMyDataObject(It.IsAny<UserObj>(), It.IsAny<Guid>()))
and well then returns? I also trid callback
_mockDataManager.Setup(m => System.Threading.Tasks.Task.FromResult(m.GetMyDataObject(It.IsAny<UserObj>(), It.IsAny<Guid>())
.Returns(System.Threading.Tasks.Task.FromResult(myData))
.Callback<MyDataObject>(o => myData = o);
myData = GetMyDataObject();
_mockDataManager.Setup(m => m.GetMyDataObject(It.IsAny<UserObj>(), It.IsAny<Guid>()).Returns(GetMyDataObject())
private GetMyDataObject() {
returns new DataSet(); //basically an empty dataset but not null
}
Given the following classes:
public class MyDataObject { }
public class UserObj { }
public class DataManager
{
public virtual MyDataObject GetMyDataObject(UserObj userObj, Guid guid)
{
throw new NotImplementedException();
}
}
class SUT
{
public DataManager DataManager { get; private set; }
public SUT(DataManager dataManager)
{
DataManager = dataManager;
}
public void Method(UserObj userobj, Guid recordid)
{
var t = System.Threading.Tasks.Task.Factory.StartNew<MyDataObject>(()=>
{
return DataManager.GetMyDataObject(userobj, recordid);
});
t.Wait();
}
}
the following mock works fine:
var mockDataManager = new Mock<DataManager>();
mockDataManager.Setup(m => m.GetMyDataObject(It.IsAny<UserObj>(), It.IsAny<Guid>()));
var sut = new SUT(mockDataManager.Object);
sut.Method(new UserObj(), Guid.Empty);
mockDataManager.VerifyAll();
Two pitfalls:
In the code you posted, you use
_mockDataManager = new Mock<_mockDataManager>();
which should be
_mockDataManager = new Mock<DataManager>(); // or whatever the name of the class is
Maybe this is just a copy/paste error, maybe not.
Also, since you use a Task here:
System.Threading.Tasks.Task.Factory.StartNew<MyDataObject>(()=>
{
return DataManager.GetMyDataObject(userobj, recordid);
}
which calls GetMyDataObject on DataManager, you have to make sure that the Task finished before you verify your mock setup. If you would remove the t.Wait(); from my code above, the test would fail, because VerifyAll would be called before the Task would start and call GetMyDataObject in the mocked object.
I've got my testing target class:
public class ApiClient
{
private IRestClient authz_rest_client;
private IRestClient api_rest_client;
// Injection feature for testing
internal ApiClient(IRestClient authz_rest_client, IRestClient api_rest_client)
{
this.authz_rest_client = authz_rest_client;
this.api_rest_client = api_rest_client;
}
//...
So, I inject my substituted RestSharp Clients as follows:
[TestFixture]
class AuthzApiClientTests
{
private ApiClient api_client;
private IRestClient authz_rest_client;
private IRestClient api_rest_client;
private IRestRequest request;
private IRestResponse<OAuth2AuthzCodeResponse> response;
[SetUp]
public void SetUp()
{
this.authz_rest_client = NSubstitute.Substitute.For<IRestClient>();
this.api_rest_client = NSubstitute.Substitute.For<IRestClient>();
this.request = NSubstitute.Substitute.For<IRestRequest>();
this.response = NSubstitute.Substitute.For<IRestResponse<OAuth2AuthzCodeResponse>>();
this.authz_rest_client.Execute<OAuth2AuthzCodeResponse>(request).Returns(response);
this.api_client = new ApiClient(this.authz_rest_client, this.api_rest_client);
this.api_client.configure(
"client_id",
"user",
"passwd"
);
}
Then, I write a test:
[Test]
public void Should_ReturnCorrectRequestTokenServiceEndpoint()
{
response.StatusCode = HttpStatusCode.Unauthorized;
response.Data = new OAuth2AuthzCodeResponse()
{
Error = StringEnum.GetStringValue(OAuth2ErrorTypes.invalid_client) //CLIENT IS NOT REGISTERED ON LEST SYSTEM.
};
this.api_client.Invoking(c => c.GrantAuthorization())
.ShouldThrow<OAuth2APIException>();
}
As you can see, I want to test my GrantAuthorization method of my ApiClient class. This method is:
IRestRequest authzcode_request = new AuthzCodeRequest(
this.settings.AuthzAuthorizeEndpoint,
this.settings.ClientId,
this.settings.ClientSecret,
this.settings.User,
this.settings.Password
);
IRestResponse<OAuth2AuthzCodeResponse> authzcode_response = this.authz_rest_client.Execute<OAuth2AuthzCodeResponse>(authzcode_request);
this.check_response(authzcode_response);
this.settings.AuthzCode = authzcode_response.Data.Code;
this.settings.AuthzCodeExpirationThreshold = DateTime.Now.AddSeconds(authzcode_response.Data.Expires_in);
The target of my test is "capture" my Execute<OAuth2AuthzCodeResponse> method in order to return my substituted response.
The problem is that, when I perform the test and I stop on this line, the result is not the response I've set previously.
I'm having trouble following through the full example, but I did notice something about the SetUp being using:
request = Substitute.For<IRestRequest>();
response = Substitute.For<IRestResponse<OAuth2AuthzCodeResponse>>();
authz_rest_client.Execute<OAuth2AuthzCodeResponse>(request).Returns(response);
The third line here says that whenever authz_rest_client.Execute<OAuth2AuthzCodeResponse>() is called with the request instance, it will return response. But request never seems to be used anywhere within the code, so Execute will never actually return that response.
Something like the following line will return response for any call to Execute<OAuth2AuthzCodeResponse>():
authz_rest_client.Execute<OAuth2AuthzCodeResponse>(null).ReturnsForAnyArgs(response);
But I'm not sure that's what you want either? Instead you might want to stub out individual calls, such as a specific response when it gets a request of type AuthzCodeRequest.
Solved!
I tried it using that:
this.authz_rest_client.Execute<OAuth2AuthzCodeResponse>(Arg.Any<IRestRequest>()).Returns(response);
This solution is similar to the pervious answer approach.
However, I not understand why not work perviouly...
I'm trying to develop a extension (IExtension<OperationContext>) for System.ServiceModel.ObjectContext using TDD. The extension is to be used as storage for a lifetime manager to be used with Windsor Castle.
The problem lies in abstracting (mocking) the OperationContext. As it is a static object that gets automatically created during runtime I don't really know how to mock it (without TypeMock - which I don't have).
An OperationContext can be newed up if I supply a channel object that implements IChannelFactory, however - that interface is scary complex, and I don't know what stuff I have to implement in a stub to get it working properly.
Hosting the service and calling it doesn't populate the OperationContext either...
[TestFixtureSetUp]
public void FixtureSetup()
{
_serviceHost = new TypeResolverServiceHost(typeof(AilDataService));
_serviceHost.AddServiceEndpoint(typeof (IAilDataService), new BasicHttpBinding(), SvcUrl);
_serviceHost.Open();
var endpointAddress = new EndpointAddress(SvcUrl);
_ailDataService = ChannelFactory<IAilDataService>.CreateChannel(new BasicHttpBinding(), endpointAddress);
}
[TestFixtureTearDown]
public void FixtureCleanup()
{
_serviceHost.Close();
}
[Test]
public void Can_Call_Service()
{
var reply = _ailDataService.GetMovexProductData("169010", new TaskSettings{MovexDatabase = "MVXCDTATST", MovexServer = "SEJULA03"});
Assert.That(reply, Is.Not.Null);
// This fails
Assert.That(OperationContext.Current!=null);
}
Any tips?
This is what I ended up doing:
[TestFixture]
public class WcfPerSessionLifestyleManagerTests
{
private const string SvcUrl = "http://localhost:8732/Design_Time_Addresses/JulaAil.DataService.WcfService/AilDataService/";
private TypeResolverServiceHost _serviceHost;
private ChannelFactory<IAilDataService> _factory;
private IAilDataService _channel;
private WindsorContainer _container;
[Test]
public void Can_Populate_OperationContext_Using_OperationContextScope()
{
using (new OperationContextScope((IContextChannel) _channel))
{
Assert.That(OperationContext.Current, Is.Not.Null);
}
}
}