I want to test a class that via a Webrequest sends texts, how can I using Moq mock the GetRequest methode, to test the GetRequest?
public class Sender
public void Send(string Message)
{
...
WebRequest myReq = GetRequest(sParmeter);
}
protected WebRequest GetRequest(string URl)
{
return WebRequest.Create(URl);
}
}
For something like this, the easy way would be to move your WebRequest instance and its action behind an interfaced intermediary.
Example:
public interface IWebRequestHandler
{
WebRequest GetRequest (string URI);
}
public class WebRequestHandler : IWebRequestHandler
{
public WebRequest GetRequest (string URI)
{
return WebRequest.Create(URl);
}
}
Your sender class should have an injectable instance of IWebRequestHandler and you can mock it with MOQ, set up expctations, verify it gets called and anything else you might want.
public class Sender
{
public IWebRequestHandler Handler{get;set;}
public void Send(string Message)
{
Handler.GetRequest(new URI(Message));//call the method with right params, just an example
}
}
One of the approaches that I was gonna suggest is the same as the response by AD.Net, but if you do not wish to modify your existing structure and still test you could do something like below:
Modify your original class as follows:
public class Sender
{
public void Send(string Message)
{
...
WebRequest myReq = GetRequest(sParmeter);
}
protected virtual WebRequest GetRequest(string URl)
{
return WebRequest.Create(URl);
}
}
and in your test project extend this class as follows:
public class MockSender: Sender
{
private WebRequest _response;
public MockSender(WebRequest response)
{
_response=response; //initialize data to be returned
}
protected override WebRequest GetRequest(string URl)
{
//return your test;
}
}
and now in your test create an instance of type MockSender and call the Send method on it.
Moq expects your class to be abstract or you to implement an interface and thus mock the interface which is what AD.Net has described
Hope this helps..
Alternative is to pass the IWebRequestCreate method in to the constructor.
public HTTPRequestFactory(IWebRequestCreate create)
{
_IWebRequestCreate = create;
}
public HTTPRequestFactory()
{
//Do nothing this is the real constructor, above is just for testing.
}
public WebRequest Create(String uri)
{
Uri _uri = new Uri("http://"+this.address+uri);
request = (HttpWebRequest)this.Create(_uri);
return request;
}
public WebRequest Create(Uri uri)
if (null == _IWebRequestCreate)
{
//use the real one
request = WebRequest.Create(uri);
}
else
{
//testing so use test one
request = _IWebRequestCreate.Create(uri);
}
return request;
}
}
Then you can use a standard test to confirm it gets called like you want.
[Test]
public void NewwebrequestCreatesWebRequest()
{
var mockCreate = new Mock<IWebRequestCreate>();
mockCreate.Setup(x => x.Create(It.IsAny<Uri>()));
HTTPRequestFactory webrequest = new HTTPRequestFactory(mockCreate.Object);
HttpWebRequest request = (HttpWebRequest)webrequest.Create(testURI);
mockCreate.VerifyAll();
}
[Test]
public void webrequestUsesAddressProperty()
{
var mockCreate = new Mock<IWebRequestCreate>();
string IP = "10.99.99.99";
Uri expected = new Uri("http://10.99.99.99/services");
mockCreate.Setup(x => x.Create(expected));
HTTPRequestFactory webrequest = new HTTPRequestFactory(mockCreate.Object);
webrequest.address = IP;
HttpWebRequest request = (HttpWebRequest)webrequest.Create(testURI);
mockCreate.VerifyAll();
}
The reason for two Create functions is that you want to pass in a string Create(string) and IWebRequestCreate requires a Create(Uri).
Edited because standard dependancy injection does not work with IWebRequestCreate. Standard pattern is Instantiate an object with the Interface and pass it in through the constructor. Since WebRequest cannot be created with a constructor and interfaces canot be instantiated, the above logic works around that.
Related
I create an interface called INetClient which supports two clients: HttpClient and WebClient ( I want that my app to be unit-testable)
The interface looks like:
public interface INetClient
{
...
void SetCredentials(ICredentials credentials);
void SetHeaders(Dictionary<HttpRequestHeader, string> headers);
void SetHeaders(Dictionary<string, string> headers);
...
}
For each of them, I created a wrapper class which implements that interface.
For web client, I did like:
public sealed class WebClientEx : WebClient, INetClient
{
public WebClientEx()
{
CookieContainer = new CookieContainer();
Encoding = Encoding.UTF8;
}
public void SetCredentials(ICredentials credentials)
{
Credentials = credentials;
}
}
and for http client:
public sealed class HttpClientEx : INetClient, IDisposable
{
private HttpClient _client;
public HttpClientEx()
{
var handler = new HttpClientHandler();
_client = new HttpClient(handler);
}
public void SetCredentials(ICredentials credentials)
{
// here, how I can set credentials ?
}
}
Later on I will use dependency injection like RegisterType<INetClient, WebClientEx> or I can change easily to RegisterType<INetClient, HttpClientEx>
How can set credentials for http client without creating new instance for it ?
If your web service is using HTTP Basic authentication, you could set the header using the HttpClient.DefaultRequestHeaders property
I have X controllers that use a API site (WebApi). I have created an ApiHelper class. Which I use in these controllers. Now my question is this. Can I make this ApiHelper a static class? I think I can because the httpClient is instanced. Or do I overlook something, and does it need to be an instanced ApiHelper. (the use of static still confuses me sometimes). Example code below.
public class HomeController : Controller
{
public async Task<string> VersionDemo()
{
var response = await ApiHelper.Call("/api/config/version");
var data = response.Content.ReadAsStringAsync();
var res = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(data.Result);
return res;
}
}
public class ConfigController : Controller
{
private async Task<List<ConfigSetting>> GetGeneralConfigurationDemo()
{
var generalConfiguration = new List<ConfigSetting>();
var response = await ApiHelper.Call("api/configuration/GetGeneralConfiguration");
var data = response.Content.ReadAsStringAsync();
generalConfiguration = JsonConvert.DeserializeObject<List<ConfigSetting>>(data.Result);
return generalConfiguration;
}
}
public static class ApiHelper
{
public static async Task<HttpResponseMessage> Call(string url)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var baseAdress = System.Configuration.ConfigurationManager.AppSettings["ApiBaseAddress"];
string apiUrl = baseAdress + url;
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(apiUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync(apiUrl);
return response;
}
}
}
Make base controller and hide http client as protected thing.
public abstract class BaseController : Controller
{
protected ApiHelper Api { get; set; }
}
Then derive your controllers from BaseController
public class ConfigController : BaseController {}
public class HomeController : BaseController {}
Note : try not to use static classes cause they make your heap littered. They are allocated in "high-frequency" heap, which is never garbage collected.
There would be no problem to leave your class static as the HttpClient stays on the method scope and thus each call to your static method will use a different HttpClient. It would not be safe if you used a static member (field or property) as it would be shared by all the callers and you would need to synchronize the access (for a multi thread usage).
After reading (httpClient your are doing it wrong , singleton pattern) and subsequently testing. I ended up using the following code. Main goal is one httpClient application wide and avoid socket exhaustion.
In my controllers where I'm in need of a httpClient I use the HttpClientSingleton.Instance see below.
And here is a BaseController you can inherit from in your controllers that are going to use your API.
public class BaseController : Controller
{
public readonly string ApiBaseAdress = System.Configuration.ConfigurationManager.AppSettings["ApiBaseAddress"];
public BaseController()
{
//Set as needed Servicepoint settings
//string SecurityProtocolTypeFromConfig = System.Configuration.ConfigurationManager.AppSettings["SecurityProtocolType"];
//SecurityProtocolType fromConfig;
//Enum.TryParse(SecurityProtocolTypeFromConfig, out fromConfig);
//ServicePointManager.SecurityProtocol = fromConfig;
//possible ServicePoint setting needed in some cases.
//ServicePointManager.Expect100Continue = false;
//ServicePointManager.MaxServicePointIdleTime = 2000;
//ServicePointManager.SetTcpKeepAlive(false, 1, 1);
}
}
And here is the HttpClientSingleton class:
public sealed class HttpClientSingleton
{
private static readonly Lazy<HttpClient> lazy = new Lazy<HttpClient>(() => new HttpClient());
public static HttpClient Instance { get { return lazy.Value; } }
private HttpClientSingleton()
{
}
}
So putting it together. Here is an example of getting some loginfo from the API.
public class MyLogController : BaseController
{
[HttpPost]
public async Task<JsonResult> log(string requestId)
{
var url = ApiBaseAdress + string.Format("/api/runs/log/{0}", requestId);
List<Log> logs = new List<Log>();
var response = await HttpClientSingleton.Instance.GetAsync(url);
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadAsStringAsync();
logs = JsonConvert.DeserializeObject<List<Log>>(result);
return Json(logs);
}
}
You can write a static helper class. If the name is ApiHelper, then add a Microsoft.AspNet.WebApi.Client reference. When your app is initialized, call the class's InitializeClient() method, and you can call the GetAsync() method if you need. The code is below:
public static class ApiHelper
{
public static HttpClient ApiClient { get; set; }
public static void InitializeClient()
{
ApiClient = new HttpClient();
ApiClient.DefaultRequestHeaders.Accept.Clear();
ApiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
public static async Task<T> GetAsync<T>(string url)
{
using (HttpResponseMessage response = await ApiHelper.ApiClient.GetAsync(url))
{
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsAsync<T>();
return result;
}
else
{
throw new Exception(response.ReasonPhrase);
}
}
}
}
I'm trying to figure out how to use FakeItEasy with the HttpClient, given the following code:
public Foo(string key, HttpClient httpClient = null)
{ .. }
public void DoGet()
{
....
if (_httpClient == null)
{
_httpClient = new HttpClient();
}
var response = _httpClient.GetAsync("user/1);
}
public void DoPost(foo Foo)
{
if (_httpClient == null)
{
_httpClient = new HttpClient();
}
var formData = new Dictionary<string, string>
{
{"Name", "Joe smith"},
{"Age", "40"}
};
var response = _httpClient.PostAsync("user",
new FormUrlEncodedContent(formData));
}
So i'm not sure how to use FakeItEasy, to fake out the HttpClient's GetAsync and PostAsync methods.
production code will not pass in the HttpClient, but the unit test will pass in the fake instance, made by FakeItEasy.
eg.
[Fact]
public void GivenBlah_DoGet_DoesSomething()
{
// Arrange.
var httpClient A.Fake<HttpClient>(); // <-- need help here.
var foo = new Foo("aa", httpClient);
// Act.
foo.DoGet();
// Assert....
}
UPDATE:
I grok that FiE (and most mocking packages) works on interfaces or virtual methods. So for this question, lets just prentend that the GetAsync and PostAsync methods are virtual ... please :)
Here's my (more or less) general purpose FakeHttpMessageHandler.
public class FakeHttpMessageHandler : HttpMessageHandler
{
private HttpResponseMessage _response;
public static HttpMessageHandler GetHttpMessageHandler( string content, HttpStatusCode httpStatusCode )
{
var memStream = new MemoryStream();
var sw = new StreamWriter( memStream );
sw.Write( content );
sw.Flush();
memStream.Position = 0;
var httpContent = new StreamContent( memStream );
var response = new HttpResponseMessage()
{
StatusCode = httpStatusCode,
Content = httpContent
};
var messageHandler = new FakeHttpMessageHandler( response );
return messageHandler;
}
public FakeHttpMessageHandler( HttpResponseMessage response )
{
_response = response;
}
protected override Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken )
{
var tcs = new TaskCompletionSource<HttpResponseMessage>();
tcs.SetResult( _response );
return tcs.Task;
}
}
Here is an example of it being used from one of my tests that expects some JSON as a return value.
const string json = "{\"success\": true}";
var messageHandler = FakeHttpMessageHandler.GetHttpMessageHandler(
json, HttpStatusCode.BadRequest );
var httpClient = new HttpClient( messageHandler );
You would now inject httpClient into your class under test (using whatever injection mechanism you prefer) and when GetAsync is called your messageHandler will spit back the result you told it to.
You could also create an AbstractHandler on which you can intercept a public abstract method. For instance:
public abstract class AbstractHandler : HttpClientHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return Task.FromResult(SendAsync(request.Method, request.RequestUri.AbsoluteUri));
}
public abstract HttpResponseMessage SendAsync(HttpMethod method, string url);
}
Then you can intercept calls to the AbstractHandler.SendAsync(HttpMethod method, string url) like:
// Arrange
var httpMessageHandler = A.Fake<AbstractHandler>(options => options.CallsBaseMethods());
A.CallTo(() => httpMessageHandler.SendAsync(A<HttpMethod>._, A<string>._)).Returns(new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent("Result")});
var httpClient = new HttpClient(httpMessageHandler);
// Act
var result = await httpClient.GetAsync("https://google.com/");
// Assert
Assert.Equal("Result", await result.Content.ReadAsStringAsync());
A.CallTo(() => httpMessageHandler.SendAsync(A<HttpMethod>._, "https://google.com/")).MustHaveHappenedOnceExactly();
More information can be found on this blog: https://www.meziantou.net/mocking-an-httpclient-using-an-httpclienthandler.htm
I did something like this when I needed to interact with the Gravatar service. I tried to use fakes/mocks but found it was impossible with HttpClient. Instead, I came up with a custom HttpMessageHandler class that lets me pre-load the expected response, along these lines:
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace Tigra.Gravatar.LogFetcher.Specifications
{
/// <summary>
/// Class LoggingHttpMessageHandler.
/// Provides a fake HttpMessageHandler that can be injected into HttpClient.
/// The class requires a ready-made response message to be passed in the constructor,
/// which is simply returned when requested. Additionally, the web request is logged in the
/// RequestMessage property for later examination.
/// </summary>
public class LoggingHttpMessageHandler : DelegatingHandler
{
internal HttpResponseMessage ResponseMessage { get; private set; }
internal HttpRequestMessage RequestMessage { get; private set; }
public LoggingHttpMessageHandler(HttpResponseMessage responseMessage)
{
ResponseMessage = responseMessage;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
RequestMessage = request;
return Task.FromResult(ResponseMessage);
}
}
}
Then my test context setup goes something like this:
public class with_fake_gravatar_web_service
{
Establish context = () =>
{
MessageHandler = new LoggingHttpMessageHandler(new HttpResponseMessage(HttpStatusCode.OK));
GravatarClient = new HttpClient(MessageHandler);
Filesystem = A.Fake<FakeFileSystemWrapper>();
Fetcher = new GravatarFetcher(Committers, GravatarClient, Filesystem);
};
protected static LoggingHttpMessageHandler MessageHandler;
protected static HttpClient GravatarClient;
protected static FakeFileSystemWrapper Filesystem;
}
Then, here's an example of a test (specification) that uses it:
[Subject(typeof(GravatarFetcher), "Web service")]
public class when_fetching_imagaes_from_gravatar_web_service : with_fake_gravatar_web_service
{
Because of = () =>
{
var result = Fetcher.FetchGravatars(#"c:\"); // This makes the web request
Task.WaitAll(result.ToArray());
//"http://www.gravatar.com/avatar/".md5_hex(lc $email)."?d=404&size=".$size;
UriPath = MessageHandler.RequestMessage.RequestUri.GetComponents(UriComponents.Path, UriFormat.Unescaped);
};
It should_make_request_from_gravatar_dot_com =
() => MessageHandler.RequestMessage.RequestUri.Host.ShouldEqual("www.gravatar.com");
It should_make_a_get_request = () => MessageHandler.RequestMessage.Method.ShouldEqual(HttpMethod.Get);
// see https://en.gravatar.com/site/check/tim#tigranetworks.co.uk
It should_request_the_gravatar_hash_for_tim_long =
() => UriPath.ShouldStartWith("avatar/df0478426c0e47cc5e557d5391e5255d");
static string UriPath;
}
You can see the full source at http://stash.teamserver.tigranetworks.co.uk/users/timlong/repos/tigra.gravatar.logfetcher/browse
FakeItEasy, like most mocking libraries, does not create proxies for non-abstract components. In the case of HttpClient, the GetAsync and PostAsync methods are neither virtual nor abstract, so you can't create stub implementations of them directly. See https://github.com/FakeItEasy/FakeItEasy/wiki/What-can-be-faked.
In this case, you need a different abstraction as a dependency - one which HttpClient can fulfill, but so could other implementations, including mocks/stubs.
This isn't answering your question directly, but I wrote a library a while back that provides an API for stubbing out requests/responses. It's pretty flexible, and supports ordered/unordered matching as well as a customisable fallback system for unmatched requests.
It's available on GitHub here: https://github.com/richardszalay/mockhttp
I'm working on a project that retrieves information from an external webservice API, but I'm not sure how I'm supposed to test it, I'm quite new at Testing and I have done just a couple of Unit Test, but as far as I know I have to mock the webservice functionality, I've been looking for info regarding this subject but haven't found anything for Windows Phone yet. What's the standard procedure for these type of cases?
Here's a simple version of what I want to test:
public async Task<List<Song>> FetchSongsAsync(String query)
{
if (String.IsNullOrEmpty(query))
return null;
string requestUrl = "webservice url";
var client = new HttpClient();
var result = await client.GetStringAsync(new Uri(requestUrl,UriKind.Absolute));
try
{
var result = JsonConvert.DeserializeObject<RootObject>(result);
return result;
}
catch (Exception)
{
return null;
}
}
Thanks!
Decouple your code from its dependencies: make content loading and its deserialization replaceable:
private readonly IClient client;
private readonly ISerializer serializer;
public YourService(IClient client, ISerializer serializer)
{
_client = client;
_serializer = serializer;
}
public async Task<List<Song>> FetchSongsAsync(String query)
{
try
{
var result = await _client.GetStringAsync(new Uri("http://example.com"));
return _serializer.DeserializeObject<RootObject>(result);
}
catch (Exception)
{
return null;
}
}
The first thing that may help is understand and use dependency injection. Basically taking any dependencies of your object/method/etc and (as it states) injecting them into the object/method/etc. For example, you are having a difficult time figuring out how to test the method because the method depends on being able to access the web service. There are a couple things you can do after this.
One thing to do is to check out mocking frameworks such as Moq.
Another thing I recently did was I added an overloaded constructor (dependency injection) that takes a HttpMessageInvoker object (note HttpClient derives from this). This way I could instantiate the class with my own response message:
public class MyLoader()
{
protected HttpMessageInvoker MessageInvoker { get; set; }
private HttpRequestMessage requestMessage;
public MyLoader() // default constructor
{
MessageInvoker = new HttpClient();
}
public MyLoader(HttpMessageInvoker httpMessageInvoker)
{
MessageInvoker = httpMessageInvoker;
}
public object DoSomething()
{
var response = await MessageInvoker.SendAsync(requestMessage, cancellationTokenSource.Token);
}
Here is my mock message invoker:
public class MockMessageInvoker : HttpMessageInvoker
{
public string ResponseString { get; set; }
public MockMessageInvoker(string responseString)
: base(new HttpClientHandler())
{
ResponseString = responseString;
}
public override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
return Task.Run<HttpResponseMessage>(() =>
{
HttpResponseMessage responseMessage = new HttpResponseMessage(
System.Net.HttpStatusCode.OK);
var bytes = Encoding.ASCII.GetBytes(ResponseString);
var stream = new System.IO.MemoryStream(bytes);
responseMessage.Content = new StreamContent(stream);
return responseMessage;
});
}
}
I can call it all like so:
MyLoader loader = new MyLoader(new MockMessageInvoker(validJsonResponse));
loader.DoSomething() // I've removed the dependency on the service and have control of the content in the response
It's quick and dirty, but does the trick.
Hope this helps.
As Richard Willis suggests in http://blog.salamandersoft.co.uk/index.php/2009/10/how-to-mock-httpwebrequest-when-unit-testing/ i'm trying to call a web request moking the behavior.
For that (I asking me if I'm messing something here) I implemented an IWebRequestCreate and extended a WebRequest and a WebResponse. (more details in link codes)
But now in my code I had a test that register (WebRequest.RegisterPrefix) a prefix:
[Test]
public void Test() {
var some = File.ReadAllBytes(#"TestData\WebService\admrond_13jan2011_14jan2011.xml");
WebRequest.RegisterPrefix("mockPrefix", new WebRequestCreateMock());
WebRequestFake request = WebRequestCreateMock.CreateRequestFake(some);
_remoteRepository.PopulateWithMeterData(_meter);
... (error in line before)
Then, I got this error: Invalid URI: The hostname could not be parsed.
But why? In my PopulateWithMeterData(Meter meter) I have this call:
WebRequest request = WebRequest.Create(urlListMeteringData);
WebResponse ws = request.GetResponse();
Some suggestion? Is interesting post my class implementations?
EDIT: as #Matthew ask:
public class WebRequestCreateMock : IWebRequestCreate {
static WebRequest _nextRequest;
static readonly object LockObject = new object();
static public WebRequest NextRequest {
get { return _nextRequest; }
set {
lock (LockObject) {
_nextRequest = value;
}
}
}
public WebRequest Create(Uri uri) {
return _nextRequest;
}
public static WebRequestFake CreateRequestFake(byte[] xmlStream) {
WebRequestFake webRequestFake = new WebRequestFake(xmlStream);
NextRequest = webRequestFake;
return webRequestFake;
}
}
public class WebRequestFake : WebRequest {
MemoryStream requestStream = new MemoryStream();
MemoryStream responseStream;
public override string Method { get; set; }
public override string ContentType { get; set; }
public override long ContentLength { get; set; }
public WebRequestFake(byte[] response) {
responseStream = new MemoryStream(response);
}
public override Stream GetRequestStream() {
return requestStream;
}
public override WebResponse GetResponse() {
return new WebReponseFake(responseStream);
}
}
public class WebReponseFake : WebResponse {
private readonly Stream _responseStream;
public WebReponseFake(Stream responseStream) {
_responseStream = responseStream;
}
public override Stream GetResponseStream() {
return _responseStream;
}
}
And the Url is something like: mockPrefix://NoMatterUrl
Since the error is "Invalid URI: The hostname could not be parsed." you are probably screwing up your Uri "mockPrefix://NoMatterUrl"
I had this problem once because I forgot to add a "/" between the domain uri and the request parameters.
Can you post exactly what your "NoMatterUri" looks like?
You need to register your prefix with a colon (':'); as in:
WebRequest.RegisterPrefix("mockPrefix:", new WebRequestCreateMock());
I have found that it's necessary to include a trailing "/" in the prefix. For instance, "test://localhost/":
[TestClass]
public class WebRequestTests
{
[TestMethod]
public void TestWebRequestCreate()
{
const string uriString = "test://localhost/foo/bar.baz?a=b&c=d";
var webRequest = new MockWebRequestCreateAssertUrl(uriString);
Assert.IsTrue(WebRequest.RegisterPrefix("test://localhost/", webRequest),
"Failed to register prefix");
Assert.IsNotNull(WebRequest.Create(uriString));
}
public class MockWebRequestCreateAssertUrl : IWebRequestCreate
{
private readonly Uri _expectedUri;
public MockWebRequestCreateAssertUrl(string uriString)
{
_expectedUri = new Uri(uriString);
}
public WebRequest Create(Uri uri)
{
Assert.AreEqual(_expectedUri, uri, "uri parameter is wrong");
return new MockWebRequestAssertUrl();
}
}
public class MockWebRequestAssertUrl : WebRequest {}
}