How do I fake System.Web.HttpClientCertificate? - c#

I want to write unit tests for a WCF web service. The service uses HttpContext.Current. I already managed to Fake it by adding a Fake Assembly to System.Web and some code like:
[Test]
public void TestMyService()
{
using (ShimsContext.Create())
{
HttpRequest httpRequest = new HttpRequest("", "http://tempuri.org", "");
HttpContext httpContext = new HttpContext(httpRequest, new HttpResponse(new StringWriter()));
System.Web.Fakes.ShimHttpContext.CurrentGet = () => { return httpContext; };
System.Web.Fakes.ShimHttpClientCertificate.AllInstances.IsPresentGet = (o) => { return true; };
}
}
But my service also needs the ClientCertificate:
if (!HttpContext.Current.Request.ClientCertificate.IsPresent) // <== Exception in unit test!
throw new Exception("ClientCertificate is missing");
_clientCertificate = new X509Certificate2(HttpContext.Current.Request.ClientCertificate.Certificate);
Now in the marked line the unit test throws a NullReferenceException:
Result Message: System.NullReferenceException : Object reference not
set to an instance of an object. Result StackTrace: at
System.Web.HttpClientCertificate..ctor(HttpContext context) at
System.Web.HttpRequest.CreateHttpClientCertificateWithAssert() at
System.Web.HttpRequest.get_ClientCertificate() at (my method) at
TestMyService()
How can I set up the ClientCertificate for the unit tests? I don´t know how the create an HttpClientCertificate object to pass by a Shim, because there is not appropriate constructor.

I found the solution myself.
Because the Exception came from the constructor of HttpClientCertificate I also had to fake it. I simple do nothing in the faked constructor:
System.Web.Fakes.ShimHttpClientCertificate.ConstructorHttpContext = (o, httpCont) => { };
Additionally in order to get a useful client certificate with HttpContext.Current.Request.ClientCertificate.Certificate in my unit test I fake:
byte[] clientCertBytes = {0x30, 0x82, 0x03, ...., 0xd3};
System.Web.Fakes.ShimHttpClientCertificate.AllInstances.CertificateGet = (o) =>
{
return clientCertBytes;
};
The clientCertBytes are the RawData of an X509Certificate2 object which I created in a debug session where I created this object from a file (could also be done from certificate store).

Related

Cannot mock the query string in HttpRequestBase for unit test

I have the following code that I need to unit test:
public ActionResult VerifyVoucherCode()
{
var model = new VerifyVoucherModel();
model.Voucher = Request.GetFirstQueryValue("token", "voucher");
The second line here is where my test fails. The code for this method is:
public static string GetFirstQueryValue(this HttpRequestBase request, params string[] keys)
{
return request.QueryString.GetFirstValue(keys);
}
My attempt to unit test this part of the method so far is:
var httpContext = CreateHttpContext();
var httpRequestBase = new HttpRequestWrapper(httpContext.Request);
var nameValueCollection = new NameValueCollection();
var controller = CreateMvcController<SignUpController>();
MockActivationCodeHelper(validationResult, controller);
For reference, the CreateHttpContext method is:
private HttpContext CreateHttpContext()
{
var httpContext = new HttpContext(
new HttpRequest("", "http://tempuri.org", "token=123"),
new HttpResponse(new StringWriter())
);
return httpContext;
}
It fails here return request.QueryString.GetFirstValue(keys); with a System Not Implemented exception for Query String. Any pointers here please?
Please take a look at flurl, while it may require some refactoring to your code, using it allows to construct http requests in a very handy and fluent way. Moreover, it makes testing your business logic that depends on calling external HTTP services extremely easy (event for edge cases)
The library has good documentation and his author is very responsive on stackoverflow.
Check out: https://flurl.dev/

C#: Moq System.NotSupportedException : Can not apply commission concerns to component because it appears to be a target-less proxy

I am trying to mock a service, and receiving the following error below in unit test. How can this be resolved? What does this error mean? Is it something maybe with await/async?
services.AddSingleton(a =>
{
var mock = new Mock<IUserResolverService>();
mock.Setup(b => b.GetUser()).Returns(5);
return mock.Object;
});
System.NotSupportedException : Can not apply commission concerns to component Common.Services.IUserResolverService_175a16cd-d798-4fbd-b343-1ba0eb5e0ad6 because it appears to be a target-less proxy. Currently those are not supported. DefaultKernel.ResolveComponent(IHandler handler, Type service, IDictionary additionalArguments, IReleasePolicy policy) IKernelInternal.Resolve(Type service, IDictionary arguments, IReleasePolicy policy) ScopedWindsorServiceProvider.GetServiceInternal(Type serviceType, Boolean isOptional) line 55
More Code Data:
private async Task<IServiceProvider> GetProvider()
{
var services = new ServiceCollection();
services.AddSingleton(new Mock<ISharedServicesApiClient>().Object);
services.AddSingleton(new Mock<IAddressValidator>().Object);
services.AddSingleton(new Mock<IAddressValidationService>().Object);
services.RegisterMappingProfiles(
new PropertyManagementDataMappingProfile(),
new ApplicationServicesMappingProfile()
);
services.AddSingleton(a =>
{
var mock = new Mock<IUserResolverService>();
mock.Setup(b => b.GetUser()).Returns(5);
return mock.Object;
});
services.AddDbContext<PropertyContext>(
a => a.UseInMemoryDatabase("TestDb").UseQueryTrackingBehavior(QueryTrackingBehavior.TrackAll),
ServiceLifetime.Singleton);
services.AddDbContext<AuditablePropertyContext>(
a => a.UseInMemoryDatabase("TestDb").UseQueryTrackingBehavior(QueryTrackingBehavior.TrackAll),
ServiceLifetime.Singleton);
services.AddSingleton<DbContext, AuditablePropertyContext>();
services.AddSingleton<DbContext, PropertyContext>();
services.AddSingleton<IAddressAppService, AddressAppService>();
services.AddSingleton<IAddressRepository, AddressRepository>();
services.AddSingleton<IPartyContactRepository, PartyContactRepository>();
services.AddSingleton<IPartyMailingAddressRepository, PartyMailingAddressRepository>();
var provider = services.GetServiceProvider();
var db = provider.GetRequiredService<PropertyContext>();
await db.AddTestData();
return provider;
}
[Fact]
public async Task AddNewAddressAlternateAddTest()
{
var provider = await GetProvider();
var manager = provider.GetRequiredService<IAddressAppService>();
var request =
SitusAndPartyAddressDataSeed.GetSingleApnRequestForAdd(AddressType.Alternate);
var result = await manager.UpdatePartyAndSitusAddresses(request);
// new AddressId is 3
Assert.True(result.Body == NewAddressId);
Following up on the "hunch" with some reasoning, you're setting up a singleton for a mocked instance of IUserResolverService, but as written you're uniquely composing and returning that mocked object using a delegate rather than just creating a single instance of the completed mock and registering it instead like you are with all the other ones. Given the blend of synchronous and asynchronous operations, it looks like your test is causing Moq to struggle with the lifecycle/creation of the object.
If we change this:
services.AddSingleton(a =>
{
var mock = new Mock<IUserResolverService>();
mock.Setup(b => b.GetUser()).Returns(5);
return mock.Object;
});
To this:
var mock = new Mock<IResolverService();
mock.Setup(b => b.GetUser()).Returns(5);
services.AddSingleton(mock.Object);
You're then passing in the actual single instance of the mock instead, which might resolve whatever is causing the issue, be it the lifecycle or late binding (or something else, but hey).

Mocking out the Data Accessor

I am trying to learn about using Moq with NUnit and IoC.
(I have my full project in BitBucket, but not sure how to share it...)
https://bitbucket.org/Cralis/skeleton/overview
I have a Logic method (Login) I am trying to test. It take a request object (Which has a username, password and IP Address). If the username and/or password are empty, the logic returns a failed status, and doesn't go to the data access layer.
So I am creating a unit test to test this.
(This my my first attempt with mocking...)
public void NotNull_Returns_True()
{
// Arrange
var request = new LoginRequest { IPAddress = "1.1.1.1", Username = "dummy", Password = "dummy" };
var response = new LoginResponse { Request = request, Success = true, Message = "", UserID = 1 };
// Setup the moc data accessor, as we don't want to gop to the concrete one.
var MockedDataAccess = new Mock<IDataAccess>();
// Set it's return value
MockedDataAccess.Setup(x => x.Login(request)).Returns(response);
// Instantiate the Logic class we're testing, using a Moc data accessor.
var logic = new BusinessLogic(MockedDataAccess.Object);
// Act
var result = logic.Login(new LoginRequest { Password = "dummy", Username = "dummy", IPAddress = "1.1.1.1" });
// Assert
Assert.AreEqual(true, result.Success);
}
This fails on the assert, as 'result' is NULL.
I'm probably doing a lot wrong. For example, I'm not sure why I need to setup the request and response objects at the top,but because all the examples I find are 'string' and 'int' inputs, it seems I can't use It.IsAny...
Could someone assist me understanding here? What am I doing wrong to get NULL as a result in the assert? I step through and the code executes as expected. But the result is null, because I never called the data accessor (It used the mock).
Edit:
Ah,
// Set it's return value
MockedDataAccess.Setup(x => x.Login(It.IsAny<LoginRequest>())).Returns(response);
That resolved the issue. I'm not sure why, so if you can help me understand and refactor this so that it's as an experienced Moq/UnitTester would expect it to look, that would be very useful.
Even though your request object has the same property values that you're passing to var result = logic.Login(new LoginRequest { Password = "dummy", Username = "dummy", IPAddress = "1.1.1.1" });, they are different objects, and so the value that you're trying to return with MockedDataAccess.Setup(x => x.Login(request)).Returns(response); isn't getting returned.
Change
var result = logic.Login(new LoginRequest { Password = "dummy", Username = "dummy", IPAddress = "1.1.1.1" });
to
var result = logic.Login(request);
The reason it worked with MockedDataAccess.Setup(x => x.Login(It.IsAny<LoginRequest>())).Returns(response); is because now you're saying "when MockedDataAccess.Login is called with any value for its parameter, return response"
Regarding the second part of your question, the reason that you need to set up the request and response objects is that by default any method that you call on a mock object will return null. Your BusinessLogic.Login method, listed below, will return the value of dataAccess.Login(). Since dataAccess is a mock, the dataAccess.Login() method will return null unless you tell it otherwise.
public LoginResponse Login(LoginRequest request)
{
// Basic validation
if (request == null)
return new LoginResponse
{
Success = false,
Message = "Empty Request"
};
if (string.IsNullOrEmpty(request.Username) || string.IsNullOrEmpty(request.Password))
return new LoginResponse
{
Success = false,
Message = "Username and/or password empty"
};
// This is returning null since dataAccess is a mock
return dataAccess.Login(request);
}
You said you think you're doing a lot wrong, but the way you have the test set up is pretty much what I do. The only thing I would change (in addition to fixing the Setup method as described above) is to use the UnitOfWork_StateUnderTest_ExpectedBehavior naming pattern for your test. For example Login_ValidLoginRequest_ShouldReturnValidLoginResponse()
The problem with this code
var result = logic.Login(new LoginRequest { Password = "dummy", Username = "dummy", IPAddress = "1.1.1.1" })
is that in the implementation of the Login method this is called
dataAccess.Login(request)
It means you have to setup the mock of DataAccess for method Login because mock does otherwise nothing. Mock if fake and needs to be setup so it works the way you need. In this case the answer of #Ben Rubin is absolutely correct.
When mock is setup like this
MockedDataAccess.Setup(x => x.Login(request)).Returns(response)
then it is necessary to call the method under test with exactly the same request object as the request which was used in setup of data access Login method, because otherwise mock will act as not setup. Here you basically saying 'when DataAccess Login is called with exactly this request, that response will be returned'.
But when mock is setup like this
MockedDataAccess.Setup(x => x.Login(It.IsAny<LoginRequest>())).Returns(response)
then it works, because here Login is setup to any LoginRequest. So the mock will in this case return response no matter what request was used. HTH
Here are more information about Mock Matching Arguments

Integration tests with dependencies on response cookies throwing System.NullReferenceException

I'm trying to find a way to write an integration test for a component which that is dependent on HttpContext and uses cookies.
My problem is an Exception is thrown when it tries to write anything to the response cookies.
Here's some code to reproduce the problem.
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Web;
using Moq;
namespace CookieTest
{
[TestClass]
public class CookieTest
{
private Mock<HttpContextBase> _httpContextMock;
[TestInitialize]
public void SetUp()
{
var request = new HttpRequest(null, "http://localhost/", "");
var stream = new MemoryStream();
var sw = new StreamWriter(stream);
var response = new HttpResponse(sw);
_httpContextMock = new Mock<HttpContextBase>();
_httpContextMock.Setup(t => t.Request).Returns(new HttpRequestWrapper(request));
_httpContextMock.Setup(t => t.Response).Returns(new HttpResponseWrapper(response));
}
[TestMethod]
public void TestCookieWrite()
{
var httpContext = _httpContextMock.Object;
var expectedValue = "value";
var cookies = httpContext.Response.Cookies;
var cookieToAdd = new HttpCookie("key", expectedValue);
// to illustrate that these are not null
Assert.IsNotNull(cookies);
Assert.IsNotNull(cookieToAdd);
// System.NullReferenceException: Object reference not set to an instance of an object.
// at System.Web.HttpCookieCollection.Add(HttpCookie cookie)
// at CookieTest.CookieTest.TestCookieWrite() in CookieTest.cs: line 41
cookies.Add(cookieToAdd);
Assert.AreEqual(expectedValue, httpContext.Response.Cookies.Get("key"));
}
}
}
The response contains a private field called _context which requires a reference to both itself and the request, if you set the field like so:
var response = new HttpResponse(sw);
response.GetType()
.GetField("_context", BindingFlags.NonPublic | BindingFlags.Instance)
.SetValue(response, new HttpContext(request, response));
_httpContextMock = new Mock<HttpContextBase>();
Then the NullReferenceException will no longer be thrown. Additionally, the test was failing as you compare the HttpCookie object with a string, you need to edit the assertion to check against the Value property like so:
Assert.AreEqual(expectedValue, httpContext.Response.Cookies.Get("key").Value);

Unit testing IAuthenticationFilter in WebApi 2

I'm trying to unit test a basic authentication filter I've written for a WebApi 2 project, but i'm having trouble mocking the HttpAuthenticationContext object required in the OnAuthentication call.
public override void OnAuthentication(HttpAuthenticationContext context)
{
base.OnAuthentication(context);
var authHeader = context.Request.Headers.Authorization;
... the rest of my code here
}
The line in the implementation that I'm trying to set up for mocking is the one that sets the authHeader variable.
However, I can't mock the Headers object because its sealed. And I can't mock the request and set a mocked headers because its a non-virtual property. And so on up the chain all the way to the context.
Has anyone successfully unit tested a new IAuthenticationFilter implementation?
I'm using Moq but I'm sure I could follow along in any mocking library if you have sample code.
Thanks for any help.
It is possible to achieve what you wanted however as none of the objects in the chain context.Request.Headers.Authorization exposes virtual properties Mock or any other framework won't provide much help for you. Here is the code for obtaining HttpAuthenticationContext with mocked values:
HttpRequestMessage request = new HttpRequestMessage();
HttpControllerContext controllerContext = new HttpControllerContext();
controllerContext.Request = request;
HttpActionContext context = new HttpActionContext();
context.ControllerContext = controllerContext;
HttpAuthenticationContext m = new HttpAuthenticationContext(context, null);
HttpRequestHeaders headers = request.Headers;
AuthenticationHeaderValue authorization = new AuthenticationHeaderValue("scheme");
headers.Authorization = authorization;
You just simply need to create in ordinary fashion certain objects and pass them to other with constructors or properties. The reason why I created HttpControllerContext and HttpActionContext instances is because HttpAuthenticationContext.Request property has only get part - its value may be set through HttpControllerContext. Using the method above you might test your filter, however you cannot verify in the test if the certain properties of objects above where touched simply because they are not overridable - without that there is no possibility to track this.
I was able to use the answer from #mr100 to get me started in solving my problem which was unit testing a couple of IAuthorizationFilter implementations. In order to effectively unit test web api authorization you can't really use AuthorizationFilterAttribute and you have to apply a global filter that check for the presence of passive attributes on controllers/actions. Long story short, I expanded on the answer from #mr100 to include mocks for the controller/action descriptors that let you test with/without the presence of your attributes. By way of example I will include the simpler of the two filters I needed to unit test which forces HTTPS connections for specified controllers/actions (or globally if you want):
This is the attribute that is applied where ever you want to force an HTTPS connection, note that it doesn't do anything (it's passive):
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class HttpsRequiredAttribute : Attribute
{
public HttpsRequiredAttribute () { }
}
This is the filter that on every request checks to see if the attribute is present and if the connection is over HTTPS or not:
public class HttpsFilter : IAuthorizationFilter
{
public bool AllowMultiple => false;
public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
List<HttpsRequiredAttribute> action = actionContext.ActionDescriptor.GetCustomAttributes<HttpsRequiredAttribute>().ToList();
List<HttpsRequiredAttribute> controller = actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<HttpsRequiredAttribute>().ToList();
// if neither the controller or action have the HttpsRequiredAttribute then don't bother checking if connection is HTTPS
if (!action.Any() && !controller.Any())
return continuation();
// if HTTPS is required but the connection is not HTTPS return a 403 forbidden
if (!string.Equals(actionContext.Request.RequestUri.Scheme, "https", StringComparison.OrdinalIgnoreCase))
{
return Task.Factory.StartNew(() => new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden)
{
ReasonPhrase = "Https Required",
Content = new StringContent("Https Required")
});
}
return continuation();
}
}
And finally a test to prove it returns a status of 403 forbidden when https is required but not used (using a lot of #mr100's answer here):
[TestMethod]
public void HttpsFilter_Forbidden403_WithHttpWhenHttpsIsRequiredByAction()
{
HttpRequestMessage requestMessage = new HttpRequestMessage();
requestMessage.SetRequestContext(new HttpRequestContext());
requestMessage.RequestUri = new Uri("http://www.some-uri.com"); // note the http here (not https)
HttpControllerContext controllerContext = new HttpControllerContext();
controllerContext.Request = requestMessage;
Mock<HttpControllerDescriptor> controllerDescriptor = new Mock<HttpControllerDescriptor>();
controllerDescriptor.Setup(m => m.GetCustomAttributes<HttpsRequiredAttribute>()).Returns(new Collection<HttpsRequiredAttribute>()); // empty collection for controller
Mock<HttpActionDescriptor> actionDescriptor = new Mock<HttpActionDescriptor>();
actionDescriptor.Setup(m => m.GetCustomAttributes<HttpsRequiredAttribute>()).Returns(new Collection<HttpsRequiredAttribute>() { new HttpsRequiredAttribute() }); // collection has one attribute for action
actionDescriptor.Object.ControllerDescriptor = controllerDescriptor.Object;
HttpActionContext actionContext = new HttpActionContext();
actionContext.ControllerContext = controllerContext;
actionContext.ActionDescriptor = actionDescriptor.Object;
HttpAuthenticationContext authContext = new HttpAuthenticationContext(actionContext, null);
Func<Task<HttpResponseMessage>> continuation = () => Task.Factory.StartNew(() => new HttpResponseMessage() { StatusCode = HttpStatusCode.OK });
HttpsFilter filter = new HttpsFilter();
HttpResponseMessage response = filter.ExecuteAuthorizationFilterAsync(actionContext, new CancellationTokenSource().Token, continuation).Result;
Assert.AreEqual(HttpStatusCode.Forbidden, response.StatusCode);
}

Categories