I have an ASP.NET Core API that I have written custom middleware for so that I can handle exceptions and write logs in a single spot. The middleware works as required when debugging via Kestrel and submitting a request from a browser or postman however in my test the response body is always a null stream.
Below is the middleware class and the test that I have written, the context.Response.WriteAsync(result) doesn't seem to flush the stream for some reason but I don't know why. Is anyone able to explain?
using System;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using Microsoft.Extensions.Logging;
using System.IO;
namespace APP.API.Middleware
{
public class ExceptionHandler
{
private readonly RequestDelegate request;
private readonly ILogger logger;
public ExceptionHandler(RequestDelegate request, ILogger<ExceptionHandler> logger)
{
this.request = request;
this.logger = logger;
}
public async Task Invoke(HttpContext context)
{
try
{
await request(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private Task HandleExceptionAsync(HttpContext context, Exception ex)
{
HttpStatusCode statusCode = HttpStatusCode.InternalServerError;
logger.LogError(ex, "Fatal exception");
var result = JsonConvert.SerializeObject(new { error = ex.Message });
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)statusCode;
return context.Response.WriteAsync(result);
}
}
}
using System.IO;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace APP.Testing.Middleware
{
[TestClass]
public class ExceptionHandler
{
[TestMethod]
public void HandleException()
{
var exceptionHandler = new API.Middleware.ExceptionHandler((innerHttpContext) =>
{
throw new System.Exception("Test exception");
}, new NullLogger<API.Middleware.ExceptionHandler>());
var context = new DefaultHttpContext();
exceptionHandler.Invoke(context).Wait();
context.Response.Body.Seek(0, SeekOrigin.Begin);
var reader = new StreamReader(context.Response.Body);
var text = reader.ReadToEnd();
}
}
}
Welcome to Stack Overflow!
Your response body is empty, because you are writing to a NullStream (not to be confused with null value).
"A Stream with no backing store. Use Null to redirect output to a stream that will not consume any operating system resources. When the methods of Stream that provide writing are invoked on Null, the call simply returns, and no data is written. Null also implements a Read method that returns zero without reading data." - Docs
Default value of Body property of HttpResponse is precisely
the NullStream. In a real scenario when an HTTP request arrives, the NullStream is replaced with HttpResponseStream. You won't be able to use it on your own as its accessibility level is set to internal.
Solution
As unit testing is only simulating real scenario, you can just replace the NullStream with any type of stream you want, for example the MemoryStream:
var exceptionHandler = new ExceptionHandler((innerHttpContext) =>
{
throw new Exception("Test exception");
}, new NullLogger<ExceptionHandler>());
var context = new DefaultHttpContext();
context.Response.Body = new MemoryStream(); // <== Replace the NullStream
await exceptionHandler.Invoke(context);
context.Response.Body.Seek(0, SeekOrigin.Begin);
var reader = new StreamReader(context.Response.Body);
var text = reader.ReadToEnd();
Don't forget to add some asserts at the end of your unit tests. After all, you want to perform some checks, right?
Assert.IsFalse(string.IsNullOrEmpty(text));
EDIT #1
As #nkosi pointed out, unless you have a really good reason, you should always call asynchronous methods with await keyword:
await exceptionHandler.Invoke(context);
and mark the method definition with async and make it return a Task:
public async Task HandleException()
That way you are avoiding deadlocks.
Something also worth pointing out (but not a necessity) is a naming convention for testing classes. Obviously, you can name it how you like, but keep it mind that when your testing class have the same name as the class you want to test, you end up with unnecessary name ambiguity. Of course you can write full name with namespace (as you did), but with my lazy nature, that's just too much so I'm using different name for testing class, for example ExceptionHandlerTests.
Related
While writing Unit Tests for one of my service classes in an ASP.Net Core Web API I needed to mock a IFormFile. Therefore I decided to mock it like this (using moq):
fileMock.Setup(x => x.CopyToAsync(It.IsAny<Stream>(), It.IsAny<CancellationToken>()))
.Callback(() =>
{
Console.WriteLine("File Copied");
})
.Returns(Task.CompletedTask);
The Method I want to test happily accepts this mock and all seemed fine until I Checked the File Location I specified for Test Purposes here:
.
This seemed a little odd to me as I expected that no file would be created (especially because my Callback and Return Statements are never touching the stream). I tried to modify the mock (e.g. without any Callback or with immediately closing the Stream) but no luck the file gets still created.
I then checked my Implementation of the File Saving Operation:
public async Task<Result> SaveFileToDiskAsync(string filePath, IFormFile file, CancellationToken token)
{
//Checking if values are correct
try
{
using (var stream = new FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(stream, token).ConfigureAwait(false);
return Result.Ok();
}
}
catch (Exception e)
{
//Logging
}
}
And here is where I am stuck. I am not seeing what is wrong with this method, especially because it seems to do the right thing with copying a file (It is just doing it at the wrong time).
Therefore my Question: Is there a better way to implement either the mock or the Method to stop the FileCreation?
var stream = new FileStream(filePath, FileMode.Create)
will create a file.
The system is tightly coupling to the actual IO implementation concern. Not an abstraction that can be mocked.
Abstract the file stream access.
public interface IFileStreamProvider {
Stream Create(string path);
Stream Open(string path);
//...
}
That should give the system the flexibility it needs to be decoupled from implementation concerns.
private readonly IFileStreamProvider disk; //populated via constructor injection.
public async Task<Result> SaveFileToDiskAsync(string filePath, IFormFile file, CancellationToken token) {
//Checking if values are correct
try {
using (var stream = disk.Create(filePath)) {
await file.CopyToAsync(stream, token).ConfigureAwait(false);
return Result.Ok();
}
} catch (Exception e) {
//Logging
}
}
And tested in isolation
//...
var disk = new MemoryStream(); //
var diskMock = new Mock<IFileStreamProvider>();
diskMock
.Setup(_ => _.Create(It.IsAny<string>()))
.Returns(disk);
//...
While the actual IFileStreamProvider.Create implementation will wrap the creation of a FileStream.
So far I've been able to setup unit testing for Azure Functions and it works great. However for my current project I need to use dynamic or imperative bindings.
https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-csharp#imperative-bindings
This leads to issues for my unit test I cannot seem to solve.
My function looks like this:
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.ServiceBus.Messaging;
using Newtonsoft.Json;
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace My.Functions
{
public static class MyFunc
{
[FunctionName("my-func")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequestMessage req,
Binder binder)
{
dynamic data = await req.Content.ReadAsAsync<object>();
byte[] bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data));
MemoryStream stream = new MemoryStream(bytes, writable: false);
var sbMsg = new BrokeredMessage(stream) { ContentType = "application/json" };
var attributes = new Attribute[]
{
new ServiceBusAccountAttribute("some-sb-account"),
new ServiceBusAttribute("some-queue-or-topic", AccessRights.Send)
};
var outputSbMessage = await binder.BindAsync<IAsyncCollector<BrokeredMessage>>(attributes);
await outputSbMessage.AddAsync(sbMsg);
return req.CreateResponse(HttpStatusCode.OK, "OK");
}
}
}
Near the end of the code of the function, I configure this binder to hold a list of BrokeredMessages. This is done by calling the BindAsync on the binder.
The attributes are dynamically set and contain a servicebus connection and topic name. This all works great when deployed to Azure so functionality-wise everything is fine.
So far so good.
However I'm stuggling with getting my test running. To be able to invoke the function, I need to provide parameters. The HttpTrigger this is pretty common, but for the Binder I don't know what to provide.
For testing I use this approach:
[TestMethod]
public void SendHttpReq()
{
// Setup
var httpRequest = GetHttpRequestFromTestFile("HttpRequest");
var sbOutput = new CustomBinder();
// Act
var response = SendToServicebus.Run(httpRequest, sbOutput);
// Assert
Assert.AreEqual(sbOutput.Count(), 1);
// Clean up
}
I use a CustomBinder inherited from Binder, because just having an instance of Binder failed in the function on the 'BindAsync' throwing 'Object reference not set to an instance of an object'. It seems the constructor of the binder is actually not meant to be called.
In the CustomBinder I override the BindAsync to return a generic list of BrokeredMessages.
public class CustomBinder : Binder
{
public override async Task<TValue> BindAsync<TValue>(Attribute[] attributes, CancellationToken cancellationToken = new CancellationToken())
{
return (TValue)((object)(new List<BrokeredMessage>()));
}
}
Not entirely surprising that also failed throwing:
InvalidCastException: Unable to cast object of type 'System.Collections.Generic.List'1[Microsoft.ServiceBus.Messaging.BrokeredMessage]' to type 'Microsoft.Azure.WebJobs.IAsyncCollector`1[Microsoft.ServiceBus.Messaging.BrokeredMessage]'.
I cannot find an implementation of the IAsyncCollector, so maybe I need to approach this differently?
My actual goal is to be able to verify the list of brokered messages, as the function would output to Azure servicebus.
As mentioned in the comments, I would agree that mocking it makes sense. You explicitely want to unit test your own code logic. With only your own business logic in mind, you may assume that the actual the actual remote operation binder.BindAsync(...) - of which you have no control over - works as expected.
Mocking it in a unit test should work with something like this:
using FluentAssertions;
using Microsoft.Azure.WebJobs;
using Microsoft.ServiceBus.Messaging;
using Xunit;
[Fact]
public async Task AzureBindAsyncShouldRetrunBrokeredMessage()
{
// arrange
var attribute = new ServiceBusAccountAttribute("foo");
var mockedResult = new BrokeredMessage()
{
Label = "whatever"
};
var mock = new Mock<IBinder>();
mock.Setup(x => x.BindAsync<BrokeredMessage>(attribute, CancellationToken.None))
.ReturnsAsync(mockedResult);
// act
var target = await mock.Object.BindAsync<BrokeredMessage>(attribute);
// assert
target.Should().NotBeNull();
target.Label.Should().Be("whatever");
}
I understand that your concern may be a full integration test. You seem to want to test the entire chain. In that case, having a unit test might prove difficult because you depend on an external system. If that is the case you might want to create a seperate integration test on top of it, by setting up a seperate instance.
Considering your function is setup as a HttpTrigger, the following should work:
# using azure functions cli (2.x), browse to the output file
cd MyAzureFunction/bin/Debug/netstandard2.0
# run a new host/instance if your function
func host start
Next, simply execute a http request to the hosted endpoint:
$ [POST] http://localhost:7071/api/HttpTriggerCSharp?name=my-func
In this case you have a clean and isolated integration setup.
Either way, I'd like to argue to either go the route of the unit test with mock OR setting up a seperate integration test setup for it.
Hope this helps...
I'm attempting to use some custom Owin middleware to modify (in this case, completely replace) the response stream in specific circumstances.
Anytime I make a call that does trigger my middleware to replace the response, everything works properly. The problem only occurs when I make a call that my middleware does not make changes to. Additionally, I have only been able to get the error to occur when the API call that is not being replaced is returning a manually created HttpResponseMessage object.
For example calling this API:
public class testController : ApiController
{
public HttpResponseMessage Get()
{
return Request.CreateResponse(HttpStatusCode.OK,new { message = "It worked." });
}
}
works fine, but this class:
public class testController : ApiController
{
public HttpResponseMessage Get()
{
HttpResponseMessage m = Request.CreateResponse();
m.StatusCode = HttpStatusCode.OK;
m.Content = new StringContent("It worked.", System.Text.Encoding.UTF8, "text/plain");
return m;
}
}
causes the error to occur. (In both cases, http://localhost:<port>/test is being called.)
The error causes either of the following:
Causes iisexpress.exe (or w3wp.exe if running in actual IIS) to crash with an Access Violation.
Throws an AccessViolationException that Visual Studio catches but is unable to do anything with as it occurs in external code. When Visual Studio does catch the exception, I see:
An unhandled exception of type 'System.AccessViolationException' occurred in System.Web.dll
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Obviously if I do not enable my middleware I do not have the issue at all. Also I have only been able to cause the issue to occur when manually creating and returning an HttpResponseMessage object as shown in the second class.
Here is my middleware class. Its currently set to simply replace the entire response stream any time someone requests the endpoint /replace regardless of if anything else in the pipeline has done anything to it.
using Microsoft.Owin;
using Owin;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using Newtonsoft.Json;
using AppFunc = System.Func<
System.Collections.Generic.IDictionary<string, object>,
System.Threading.Tasks.Task
>;
namespace TestOwinAPI
{
public class ResponseChangeMiddleware
{
AppFunc _next;
public ResponseChangeMiddleware(AppFunc next, ResponseChangeMiddlewareOptions opts)
{
_next = next;
}
public async Task Invoke(IDictionary<string,object> env)
{
var ctx = new OwinContext(env);
// create a new memory stream which will replace the default output stream
using (var ms = new MemoryStream())
{
// hold on to a reference to the actual output stream for later use
var outStream = ctx.Response.Body;
// reassign the context's output stream to be our memory stream
ctx.Response.Body = ms;
Debug.WriteLine(" <- " + ctx.Request.Path);
// allow the rest of the middleware to do its job
await _next(env);
// Now the request is on the way out.
if (ctx.Request.Path.ToString() == "/replace")
{
// Now write new response.
string json = JsonConvert.SerializeObject(new { response = "true", message = "This response will replace anything that the rest of the API might have created!" });
byte[] jsonBytes = System.Text.Encoding.UTF8.GetBytes(json);
// clear everything else that anything might have put in the output stream
ms.SetLength(0);
// write the new data
ms.Write(jsonBytes, 0, jsonBytes.Length);
// set parameters on the response object
ctx.Response.StatusCode = 200;
ctx.Response.ContentLength = jsonBytes.Length;
ctx.Response.ContentType = "application/json";
}
// In all cases finally write the memory stream's contents back to the actual response stream
ms.Seek(0, SeekOrigin.Begin);
await ms.CopyToAsync(outStream);
}
}
}
public static class AppBuilderExtender
{
public static void UseResponseChangeMiddleware(this IAppBuilder app, ResponseChangeMiddlewareOptions options = null )
{
if (options == null)
options = new ResponseChangeMiddlewareOptions();
app.Use<ResponseChangeMiddleware>(options);
}
}
public class ResponseChangeMiddlewareOptions
{
}
}
I've done the obvious - a full night of RAM testing (all good), and trying on another system (it occurred there too).
Additionally, the error is not consistent - it occurs about half the time. In other words, often I can get one or two successful requests through, but eventually, the error occurs.
Finally, if I put a breakpoint in my program right before the memory stream copy in my middleware, and slowly step through the code, the error never occurs. This indicates to me that I must be hitting some kind of race condition, and it has to be related to the fact that I'm playing with MemoryStreams.
Any ideas?
Oh, my.
I'm not sure if changing this is the right thing to do, but it definitely fixed the problem:
await ms.CopyToAsync(outStream);
to
ms.CopyTo(outStream);
My only guess is that somehow the app was closing the MemoryStream before the async call had completed copying it, which would make sense.
I have a class that depends on the HttpClient from Windows.Web.Http (Windows 10 UAP App). I want to unit test and therefore I need to "mock" the HttpClient to setup what a Get-Call should return. I started with a "simple" unit test with a HttpClient using a handwritten-mocked IHttpFilter and IHttpContent. It's not working as expected and I get a InvalidCastException in the Test-Explorer.
The unit test looks like:
[TestMethod]
public async Task TestMockedHttpFilter()
{
MockedHttpContent mockedContent = new MockedHttpContent("Content from MockedHttpContent");
MockedHttpFilter mockedHttpFilter = new MockedHttpFilter(HttpStatusCode.Ok, mockedContent);
HttpClient httpClient = new HttpClient(mockedHttpFilter);
var resultContentTask = await httpClient.SendRequestAsync(new HttpRequestMessage(HttpMethod.Get, new Uri("http://dontcare.ch"))).AsTask().ConfigureAwait(false);
// Test stops here, throwing System.InvalidCastException: Specified cast is not valid
// Code not reached...
var result = await resultContentTask.Content.ReadAsStringAsync();
Assert.AreEqual("Content from MockedHttpContent", result);
}
I implemented IHttpFilter in MockedHttpFilter:
public class MockedHttpFilter : IHttpFilter
{
private HttpStatusCode _statusCode;
private IHttpContent _content;
public MockedHttpFilter(HttpStatusCode statusCode, IHttpContent content)
{
_statusCode = statusCode;
_content = content;
}
public IAsyncOperationWithProgress<HttpResponseMessage, HttpProgress> SendRequestAsync(HttpRequestMessage request)
{
return AsyncInfo.Run<HttpResponseMessage, HttpProgress>((token, progress) =>
Task.Run<HttpResponseMessage>(()=>
{
HttpResponseMessage response = new HttpResponseMessage(_statusCode);
response.Content = _content;
return response; // Exception thrown after return, but not catched by code/debugger...
}));
}
}
I implemented IHttpContent in MockedHttpContent:
public class MockedHttpContent : IHttpContent
{
private string _contentToReturn;
public MockedHttpContent(string contentToReturn)
{
_contentToReturn = contentToReturn;
}
public HttpContentHeaderCollection Headers
{
get
{
return new HttpContentHeaderCollection();
}
}
public IAsyncOperationWithProgress<string, ulong> ReadAsStringAsync()
{
return AsyncInfo.Run<string, ulong>((token, progress) => Task.Run<string>(() =>
{
return _contentToReturn;
}));
}
}
The error in the Test-Explorer result view:
Test Name: TestMockedHttpFilter
Test FullName: xxx.UnitTests.xxxHttpClientUnitTests.TestMockedHttpFilter
Test Source: xxx.UnitTests\xxxHttpClientUnitTests.cs : line 22
Test Outcome: Failed
Test Duration: 0:00:00.1990313
Result StackTrace:
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
at xxx.UnitTests.xxxHttpClientUnitTests.<TestMockedHttpFilter>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Result Message: Test method xxx.UnitTests.xxxHttpClientUnitTests.TestMockedHttpFilter threw exception:
System.InvalidCastException: Specified cast is not valid.
First, not sure why the exception is thrown / what I'm doing wrong. Maybe someone can point me in the right direction or give a hint what to check / test next?
Second, is there a better way to unit test code with a HttpClient dependency (Windows 10 UAP)?
You're unit test doesn't make sense, you aren't really testing your class, but instead you are attempting to test the HttpClient class. I'm going to assume a few things since we don't have the method under test in your question; I'm assuming that you do something like the following:
public async Task<MyCustomClass> MethodUnderTest()
{
// ...
using (var client = new HttpClient(...))
{
// ...
var json = response.Content.ReadAsStringAsync();
return JsonConvert.Deserialize<MyCustomClass>(json);
}
}
If this is the case, then you have to understand that your class does not accept certain dependencies. You can either alter the class so that every external dependency is injected, but that may be a slight overkill... do you really want anyone who consumes and instantiates your class to have to supply an HttpClient to you? So, the better alternative is to use a mocking framework which can mock a dependency of a concrete class; most mocking frameworks can handle mocking interfaces (those are easy), but very few can handle mocking concrete classes.
The framework I would suggest to use is the Microsoft Fakes framework. Microsoft Fakes supports Shims (Isolation) and Stubs (Mocks). Isolation is what you need in order to control member calls of concrete classes.
So, given my example, which members need to be controlled?
HttpResponseMessage.Content_Get
HttpContent.ReadAsStringAsync
I don't think you need to alter the behavior of the JsonConvert.Deserialize<T>() member, but you could if you wanted to. The Microsoft Fakes framework is a bit daunting at first, but once you start using it and get it to work, it'll become easier to use. Alternatively, you can use other frameworks which support Isolation:
JustMock from Telerik
TypeMock Isolator
Maybe others exist, I'm not familiar with them.
It seems you're not using an AsTask overload which is matching the return value of httpClient.SendRequestAsync(...)
try changing this
var resultContentTask = await httpClient.SendRequestAsync(new HttpRequestMessage(HttpMethod.Get, new Uri("http://dontcare.ch"))).AsTask().ConfigureAwait(false);
to this
var resultContentTask = await httpClient.SendRequestAsync(new HttpRequestMessage(HttpMethod.Get, new Uri("http://dontcare.ch"))).AsTask<IAsyncOperationWithProgress<HttpResponseMessage, HttpProgress>>().ConfigureAwait(false);
Easiest solution would be using this library for mocking HttpClient
https://github.com/richardszalay/mockhttp
PM> Install-Package RichardSzalay.MockHttp
I Also tested it with your attached code
//Arrange
var mockHttp = new MockHttpMessageHandler();
mockHttp.When("http://dontcare.ch")
.Respond("application/txt", "Content from MockedHttpContent"); // Respond with content
var client = mockHttp.ToHttpClient();
//Act
var response = await client.GetAsync("http://dontcare.ch");
var result = await response.Content.ReadAsStringAsync();
//Assert
Assert.AreEqual("Content from MockedHttpContent", result);
I'm looking for some advice on writing some unit tests for the code below. Implementation aside (it's not my code, but I've been tasked to retroactively write some tests for it) could someone suggest how I might test this? I'm not using nUnit or a similar framework; I am using the testing tools built into Visual Studio.
I'm fairly new to writing unit tests, but I imagine I should at least test the following:
Valid response passed into SaveFormBrokerResponse() method
Test for valid exceptions thrown by the catch()
Testing the started Task, but not sure how to do this
I've stripped just a bit out of this function, mostly to do with instantiation and population of some objects:
public void SaveResponse(IForm form, bool isLive, HttpRequestBase request)
{
try
{
var response = new FormBrokerResponses();
// Initialize some vars on response
using (var memory = new MemoryStream())
{
var serializer = new DataContractSerializer(typeof(FormKeyValue[]));
serializer.WriteObject(memory, request.Form.AllKeys.Select(r => new FormKeyValue(r, request.Form[r])).ToArray());
memory.Flush();
memory.Seek(0, SeekOrigin.Begin);
response.Values = Encoding.UTF8.GetString(memory.ToArray());
}
_dataHandler.SaveFormBrokerResponses(response);
}
catch (Exception ex)
{
throw new Exception("boom explosions");
}
Task.Factory.StartNew(() => DispatchFormResponseViaEmail(form, isLive, request.Form.AllKeys.ToDictionary(r => r, r => (object)request.Form[r])));
}
I realize that testing void implementations is tricky and questionable and that there are some integration test concerns here, but that said I can't (currently) change the implementation and need to write tests for what I have.
You can't. You've created a method that fires off an asynchronous operation and then doesn't expose any means of observing the completion/results of that operation to the caller. There are lots of ways of doing this (returning a task, accepting a callback, an event, etc.) but you need to do something for the caller to be able to observe the results of the asynchronous operation. If the method doesn't expose anything, then there is nothing that the caller can reliably do.
If you are allowed to make slight modifications to the code I would do the following which is just a small change anyway :
public void SaveResponse(IForm form, bool isLive, HttpRequestBase request)
{
try
{
var response = new FormBrokerResponses();
// Initialize some vars on response
using (var memory = new MemoryStream())
{
var serializer = new DataContractSerializer(typeof(FormKeyValue[]));
serializer.WriteObject(memory, request.Form.AllKeys.Select(r => new FormKeyValue(r, request.Form[r])).ToArray());
memory.Flush();
memory.Seek(0, SeekOrigin.Begin);
response.Values = Encoding.UTF8.GetString(memory.ToArray());
}
_dataHandler.SaveFormBrokerResponses(response);
}
catch (Exception ex)
{
throw new Exception("boom explosions");
}
Dispatch(form,isLive,request);
}
virtual void Dispatch(IForm form, bool isLive, HttpRequestBase request){
Task.Factory.StartNew(() => DispatchFormResponseViaEmail(form, isLive, request.Form.AllKeys.ToDictionary(r => r, r => (object)request.Form[r])));
}
I don't know what this class is named so suppose the class is named DutClass, you can now derive a different implementation of that class as following:
public class UnitTestClass : DutClass{
override Dispatch(){
//don't do anything or set a state variable that this method was called
}
}
Then instead of testing the DutClass you test the UnitTextClass which has a different implementation of the Dispatch method and does not start a Task at all. You can then test that in fact this method was called, test for the exceptions and so on.