Mock testing IDistrubutedCache - c#

I am trying to test a function that uses IDistrubtedMemory cache, I've configured the cache mock object's Get and Set and the Get function seems to be functioning, but when I set a new memory object, it never gets returned. Below is the test
-- Test code
[Fact]
public async void Can_AddToMonitoring()
{
var cacheKey = "Simulator";
var tList = new List<string>();
var tNumber = Guid.NewGuid().ToString().Substring(0, 6);
// Setup - Add mock objects that are needed
var mockLogger = new Mock<ILogger<TSimulatorService>>();
var mockCache = new Mock<IDistributedCache>();
mockCache.Setup(cacheMoc => cacheMoc.Get(It.IsAny<string>()))
.Returns(Mock.Of<byte[]>);
mockCache.Setup(cacheMoc => cacheMoc.Set(It.IsAny<string>(), It.IsAny<byte[]>(), null));
var mockEventBus = new Mock<IEventBus>();
var tSimulationService = new TSimulatorService(mockLogger.Object, mockEventBus.Object, mockCache.Object);
await tSimulationService.AddToMonitoring(tNumber);
// Assert - Verify the MemoryCache contains the tag we sent over
var testTag = await tSimulationService.GetTsForPublish();
var tSimulations = testTag as TSimulation[] ?? testT.ToArray();
tSimulations.ShouldNotBeEmpty();
tSimulations.ShouldContain( t => t.TNumber.Equals(tNumber));
}
This is the method I am attempting to test
public async Task AddToMonitoring(string tNumber)
{
var cacheList = await GetMonitoredTListFromCache();
var tList = cacheList.ToList();
if (!tagList.Contains(tNumber))
tList.Add(tNumber);
await _cache.SetStringAsync(tListCacheKey, JsonConvert.SerializeObject(tList));
}
Everything appears to work until I get to the Assert part of the test, when I attempt to pull the object I set, all I get is a null return and i am not entirely sure of why?

Related

Unit test result in null object while testing a web api 2

I am new to MS Unit Testing and Moq objects. I am trying to test my Web API 2 controller. I have given below my unit test and controller code. While stepping through the code, it doesn't even go to the GetDeliveryCodeStrategy method.
[TestMethod]
public void CreateDelivery_ShouldReturnDeliveryCode()
{
Mock<IDeliveryStrategy> deliveryStrategy = new Mock<IDeliveryStrategy>
();
Mock<IDeliveryCode> deliveryCode = new Mock<IDeliveryCode>();
var controller = new DeliveryCodeController(deliveryStrategy.Object,
deliveryCode.Object);
var controllerContext = new HttpControllerContext();
var request = new HttpRequestMessage();
request.Headers.Add("appToken", "a57ffa87-950e-40f4-b965-17788becac7d");
controllerContext.Request = request;
controller.ControllerContext = controllerContext;
var result = controller.CreateDelivery(50) as
CreatedNegotiatedContentResult<IDeliveryCode>;
Assert.IsNotNull(result);
}
public class DeliveryCodeController : ApiController
{
IDeliveryStrategy _deliveryBatch;
IDeliveryCode _deliveryCode;
//Constructor dependency injection through Autofac
public DeliveryCodeController(IDeliveryStrategy DeliveryBatch,
IDeliveryCode deliveryCode)
{
_deliveryBatch = DeliveryBatch;
_deliveryCode = deliveryCode;
}
[HttpPost]
[Route("api/DeliveryCode/{percentage}")]
public IHttpActionResult CreateDelivery(int percentage)
{
String appToken = String.Empty;
if (Request.Headers.TryGetValues("appToken", out IEnumerable<String>
headerValues))
{
appToken = headerValues.FirstOrDefault();
}
if (!String.IsNullOrEmpty(appToken)))
{
IDeliveryContext deliveryContext =
_deliveryBatch.GetDeliveryCodeStrategy(percentage);
_deliveryCode.Code = deliveryContext.Create();
return Created(Request.RequestUri.ToString(), _deliveryCode);
}
else
{
return Content(HttpStatusCode.Forbidden, new Error { message = "The App
Token is not valid." });
}
}
}
When I do the "Debug Test" and step through the code, the deliveryContext
object comes as null in the code IDeliveryContext deliveryContext =
_deliveryBatch.GetDeliveryCodeStrategy(percentage);
You have to set up the Mock to return a certain value:
IDeliveryContext deliveryContext = // ???? - whatever you want it to be.
// Could be another Mock.
// This is what the Mock will return.
Mock<IDeliveryStrategy> deliveryStrategy = new Mock<IDeliveryStrategy>();
deliveryStrategy.Setup(x => x.GetDeliveryCodeStrategy(It.IsAny<decimal>()))
.Returns(deliveryContext);
This tells the Mock that that when its GetDeliveryCodeStrategy method is called, it should return the specified IDeliveryContext. Depending on what you're trying to do, that could be another Mock. (Mocks that return mocks are undesirable, but if you're starting out I'd file that detail away and come back to it.)
I'm guessing that percentage is a decimal. It.IsAny<decimal>() means that the mock doesn't care what the value is. That's usually okay because what you're testing is what your class does with the object returned by the mock.
You need to call Setup() on mock objects for the methods that you want to use:
var deliveryStrategy = new Mock<IDeliveryStrategy>();
deliveryStrategy.Setup(x => x.GetDeliveryCodeStrategy(It.IsAny<int>))
.Returns(AMockOfDeliveryContext); //you need to mock it beforehand so you can
//use the object here

Testing HttpModule wtih Response.Filter and Response.Write

I'm working on an Http Module that simply records the response time and size and then appends the results to the response body.
My module looks something like this:
public override void PreRequestHandlerExecute(HttpContextBase context)
{
// Add a filter to capture response stream
context.Response.Filter = new ResponseSniffer(context.Response.Filter);
}
public override void ApplicationEndRequest(HttpContextBase context)
{
....
context.Response.Write(builder.ToString());
}
I now wish to unit test this module. I'm very new to unit testing. I've adapted code from o2platform to get a moq httpcontext and that works so far. However, the response filter does seem to get set in Pre and the response body is what I initialized it has from the test setup.
I've tried a handful options (and read a lot of stuff) but none of these seemed to work:
public Mock<HttpResponseBase> MockResponse { get; set; }
...
var outputStream = new MemoryStream();
var filter = new MemoryStream();
//MockResponse.Setup(response => response.OutputStream).Returns(GetMockStream(outputStream).Object);
//MockResponse.Setup(response => response.Filter).Returns(GetMockStream(filter).Object);
MockResponse.Setup(response => response.OutputStream).Returns(() => outputStream);
//MockResponse.SetupSet(response => response.OutputStream = It.IsAny<Stream>()).Returns(() => outputStream);
MockResponse.Setup(response => response.Filter).Returns(() => filter);
MockResponse.SetupSet(response => response.Filter = It.IsAny<Stream>());
MockResponse.SetupSet(response => response.Filter = It.IsAny<ResponseSniffer>());
Test Method
[TestMethod]
public void TestMethod1()
{
var mockHttpContext = new MoqHttpContext();
var httpContext = mockHttpContext.HttpContext();
var html = #"<html>
<head></head>
<body>
<h1>Hello World</h1>
</body>
</html>";
httpContext.ResponseWrite(html);
httpContext.StreamWrite(httpContext.Response.Filter, html);
var module = new Module();
module.PreRequestHandlerExecute(mockHttpContext.HttpContext());
module.ApplicationBeginRequest(mockHttpContext.HttpContext());
module.ApplicationEndRequest(mockHttpContext.HttpContext());
var responseRead = httpContext.ResponseRead(); //extension method to get output stream
var b = 1; //put breakpoint here
}
I realize the test needs to Assert rather then the breakpoint. I also realize that the test should be broken up a bit.
Code Repo
Github
Let's see at the following statement in Module.ApplicationEndRequest() method:
context.Response.Write(builder.ToString());
When this code is executed from Unit Test, context.Response is a mock that you set up in MoqHttpContext.CreateBaseMocks():
MockResponse = new Mock<HttpResponseBase>();
// ...
MockContext.Setup(ctx => ctx.Response).Returns(MockResponse.Object);
You can't expect that you call a Write() method on a mock and then can read the same data back. Mock is a fake object. Its default implementation of Write() method does nothing, and passed data is just lost.
To fix the problem, you could setup a callback on Response mock that will write passed data to a stream and then return it back on read. You are actually very close to it.
In MoqHttpContext class declare a stream where you will save the data:
public class MoqHttpContext
{
private readonly MemoryStream _outputStream = new MemoryStream();
// ...
}
Then in CreateBaseMocks() method setup a callback:
public MoqHttpContext CreateBaseMocks()
{
// ...
MockResponse = new Mock<HttpResponseBase>();
MockResponse.Setup(x => x.Write(It.IsAny<string>())).Callback<string>(s =>
{
var data = Encoding.ASCII.GetBytes(s);
_outputStream.Write(data, 0, data.Length);
_outputStream.Flush();
_outputStream.Position = 0;
});
// ...
}
You also should remove a line that sets inputStream position to 0 in MoqHttpContextExtensions.StreamWrite(), so that html data that you write in UnitTest1.TestMethod1() is appended, not overwritten:
public static HttpContextBase StreamWrite(this HttpContextBase httpContextBase, Stream inputStream, string text)
{
if (inputStream == null) inputStream = new MemoryStream();
var streamWriter = new StreamWriter(inputStream);
inputStream.Position = inputStream.Length;
streamWriter.Write(text);
streamWriter.Flush();
// Remove this line
//inputStream.Position = 0;
return httpContextBase;
}
That's it. Now if you check value of responseRead in the test, you will see that data appended by Http module is there.
UPDATE (Fixing problem with a filter)
There are 3 different issues with current code that prevent correct work of a filter from UT.
You tried handful options for mocking Filter property, however none of them seems correct. The correct way to mock property getter with Moq is:
MockResponse.SetupGet(response => response.Filter).Returns(filter);
Remove all other statements for mocking response.Filter, but don't add above statement yet, it's not a final version.
You have following check in Module.ApplicationEndRequest() method:
if (context.Response.Filter is ResponseSniffer filter)
{
// ...
When UT is executed, context.Response.Filter is a MemoryStream not a ResponseSniffer. Setter that is called in Module constructor:
context.Response.Filter = new ResponseSniffer(context.Response.Filter);
will not actually affect value returned by Filter getter because it's a mock that currently always return instance of MemoryStream that you setup with SetupGet. To fix this problem you should actually emulate property behavior: save the value passed to setter and return it in the getter. Here is a final setup of response.Filter property:
Stream filter = new MemoryStream();
MockResponse.SetupSet(response => response.Filter = It.IsAny<Stream>()).Callback<Stream>(value => filter = value);
MockResponse.SetupGet(response => response.Filter).Returns(() => filter);
Make sure you have deleted all other mocks of response.Filter property.
The final problem that you should fix - is the order of Module invocations from UT. Currently the order is the following:
httpContext.StreamWrite(httpContext.Response.Filter, html);
// ...
var module = new Module();
module.PreRequestHandlerExecute(mockHttpContext.HttpContext());
But PreRequestHandlerExecute sets Response.Filter with an instance of ResponseSniffer. So when httpContext.StreamWrite above it is called, httpContext.Response.Filter holds actually instance of MemoryStream, not ResponseSniffer. So the last fix you should make is to change the order of statements in UT body:
// ...
var module = new Module();
module.PreRequestHandlerExecute(mockHttpContext.HttpContext());
httpContext.ResponseWrite(html);
httpContext.StreamWrite(httpContext.Response.Filter, html);
module.ApplicationBeginRequest(mockHttpContext.HttpContext());
module.ApplicationEndRequest(mockHttpContext.HttpContext());
// ...
UPDATE (UT Redesign)
At this point your UT should work. However current test is very cumbersome. The fact that it takes so much time to understand why it does not work proves it. Such tests are very hard to maintain and fix, they become a real pain over time.
Moreover it's rather Integration test than Unit test, because it invokes several of classes with different functionality - ResponseSniffer and Module.
You should strongly consider redesign of current test. And the good start is to make separate tests for ResponseSniffer and Module classes.
Most valuable test for ResponseSniffer is the one that verifies that written data is registered in RecordStream:
[TestClass]
public class ResponseSnifferTests
{
[TestMethod]
public void Write_WritesDataToRecordStream()
{
// Arrange
var inData = new byte[] { 0x01 };
var target = new ResponseSniffer(Mock.Of<Stream>());
// Act
target.Write(inData, 0, inData.Length);
// Assert
target.RecordStream.Position = 0;
var outData = new byte[inData.Length];
int outSize = target.RecordStream.Read(outData, 0, outData.Length);
Assert.AreEqual(inData.Length, outSize);
CollectionAssert.AreEqual(inData, outData);
}
}
As regards Module class, there are several checks that should be made:
PreRequestHandlerExecute() sets Response.Filter with instance of ResponseSniffer.
ApplicationBeginRequest() adds Stopwatch to context.Items dictionary.
ApplicationEndRequest() writes request info to the response.
UT approach implies checking of these facts in separate tests. Here are samples of such 3 tests:
[TestClass]
public class ModuleTests
{
[TestMethod]
public void PreRequestHandlerExecuteShouldSetResponseSnifferAsFilter()
{
// Arrange
Stream filter = null;
Mock<HttpResponseBase> httpResponseMock = new Mock<HttpResponseBase>();
httpResponseMock.SetupSet(response => response.Filter = It.IsAny<Stream>()).Callback<Stream>(value => filter = value);
Mock<HttpContextBase> httpContextStub = new Mock<HttpContextBase>();
httpContextStub.SetupGet(x => x.Response).Returns(httpResponseMock.Object);
var target = new Module();
// Act
target.PreRequestHandlerExecute(httpContextStub.Object);
// Assert
Assert.IsNotNull(filter);
Assert.IsInstanceOfType(filter, typeof(ResponseSniffer));
}
[TestMethod]
public void ApplicationBeginRequestShouldStoreStopwatchInContextItems()
{
// Arrange
var items = new Dictionary<string, object>();
Mock<HttpContextBase> httpContextStub = new Mock<HttpContextBase>();
httpContextStub.SetupGet(x => x.Items).Returns(items);
var target = new Module();
// Act
target.ApplicationBeginRequest(httpContextStub.Object);
// Assert
Assert.IsTrue(items.ContainsKey("X-ResponseTime"));
Assert.IsInstanceOfType(items["X-ResponseTime"], typeof(Stopwatch));
}
[TestMethod]
public void ApplicationEndRequestShouldAddRequestInfoToResponse()
{
// Arrange
Mock<HttpRequestBase> httpRequestMock = new Mock<HttpRequestBase>();
httpRequestMock.SetupGet(x => x.FilePath).Returns("/test");
string writtenData = null;
Mock<HttpResponseBase> httpResponseMock = new Mock<HttpResponseBase>();
httpResponseMock.Setup(x => x.Write(It.IsAny<string>())).Callback<string>(s => writtenData = s);
Mock<HttpContextBase> httpContextStub = new Mock<HttpContextBase>();
httpContextStub.SetupGet(x => x.Request).Returns(httpRequestMock.Object);
httpContextStub.SetupGet(x => x.Response).Returns(httpResponseMock.Object);
httpContextStub.SetupGet(x => x.Items).Returns(new Dictionary<string, object> { ["X-ResponseTime"] = new Stopwatch() });
var target = new Module();
// Act
target.ApplicationEndRequest(httpContextStub.Object);
// Assert
Assert.IsTrue(Regex.IsMatch(writtenData, #"Response Size: \d+ bytes<br/>"));
Assert.IsTrue(Regex.IsMatch(writtenData, #"Module request time: \d+ ms"));
}
}
As you see, the tests are pretty simple and straightforward. You don't need those MoqHttpContext and MoqHttpContextExtensions with a lot of mocks and helpers anymore. Another benefit - if some of the tests get broken, it's much easier to identify the root cause and fix it.
If you are new to Unit Testing and are looking for good source of info on it, I strongly suggest book The Art of Unit Testing by Roy Osherove.

Moq Callback not working with 3 parameter method

I'm trying to understand why the following unit test does not execute the callback. If I modify the code so that the UpdateWorklowInstanceState method only contains 2 parameters (Guid and IList), it works. However, something about having 3 parameters interferes.
What I mean by interferes is that the Callback doesn't appear to get executed. There's no error message. I expect to see the "Error Occurred" message but instead receive an "Element Updated" message which means the Callback did not populate the resultMessages with the NotificationMessage.
public void BusinessObjectReturnsErrorNotification_ReturnErrorMessage()
{
var workflowInstanceGuid = Guid.NewGuid();
var workflowElementModel = new WorkflowElementModel
{
ElementName = "ValidName",
WorkflowInstanceId = workflowInstanceGuid.ToString()
};
var workflowElementInstance = new WorkflowElementInstance
{
ElementName = workflowElementModel.ElementName,
FullDescription = "Full Description",
SummaryDescription = "Summary Description",
RefTime = DateTime.Now,
ElementType = "ElementType"
};
var mockWebApiBusinessObject = new Mock<IWebApiBusinessObject>();
mockWebApiBusinessObject.Setup(m => m.UpdateWorkflowInstanceState(workflowInstanceGuid, workflowElementInstance, It.IsAny<List<NotificationMessage>>()))
.Callback<Guid, WorkflowElementInstance, IList<NotificationMessage>>(
(workflowInstanceId, elementDetails, resultMessages) =>
{
resultMessages.Add(new NotificationMessage("An Error Occured!", MessageSeverity.Error));
});
var controller = new WorkflowElementController(mockWebApiBusinessObject.Object);
var result = controller.UpdateWorkflowElement(workflowElementModel);
Assert.AreEqual("An Error Occured!", result.Content.ReadAsStringAsync().Result);
}
Method under test:
[HttpPost]
[ActionName("UpdateWorkflowElement")]
public HttpResponseMessage UpdateWorkflowElement(WorkflowElementModel workflowElementModel)
{
if (!ModelState.IsValid || workflowElementModel == null)
{
return new HttpResponseMessage(HttpStatusCode.BadRequest);
}
var response = new HttpResponseMessage(HttpStatusCode.OK);
string responseMessage;
if (workflowElementModel.RefTime == DateTime.MinValue)
{
workflowElementModel.RefTime = DateTime.UtcNow;
}
var resultMessages = new List<NotificationMessage>();
var instanceId = new Guid();
if (string.IsNullOrWhiteSpace(workflowElementModel.WorkflowInstanceId) ||
string.IsNullOrWhiteSpace(workflowElementModel.ElementName))
{
responseMessage = "WorkflowInstanceId or ElementName are null or empty";
}
else if (!Guid.TryParse(workflowElementModel.WorkflowInstanceId, out instanceId))
{
responseMessage = "WorkflowInstanceId is not a valid Guid";
}
else
{
var element = new WorkflowElementInstance
{
ElementName = workflowElementModel.ElementName,
RefTime = workflowElementModel.RefTime,
SummaryDescription = workflowElementModel.SummaryDescription ?? "",
FullDescription = workflowElementModel.FullDescription ?? ""
};
_webApiBusinessObject.UpdateWorkflowInstanceState(instanceId, element, resultMessages);
responseMessage = "Element Updated";
}
if (NotificationMessage.HasErrors(resultMessages))
{
responseMessage = resultMessages.Find(m => m.Status == MessageSeverity.Error).Message;
}
response.Content = new StringContent(responseMessage);
return response;
}
It does not work in you case for 3 parameters because you are mixing the expression parameter types.
It.IsAny<List<NotificationMessage>>()
in the setup, as apposed to the
IList<NotificationMessage>
in the callback parameters.
That means the setup expression parameters does not match the callback expression parameters so the call back is not going to be called.
Stick with one type so either go with the List<NotificationMessage> for both
You are also creating new instances of the parameters in the method under test, which would be different instance to the ones used in the setup. That is why the call back is not working. To prove it. Use It.IsAny<>() for all the parameters and it should work
mockWebApiBusinessObject
.Setup(m => m.UpdateWorkflowInstanceState(It.IsAny<Guid>(), It.IsAny<WorkflowElementInstance>(), It.IsAny<List<NotificationMessage>>()))
.Callback<Guid, WorkflowElementInstance, List<NotificationMessage>>(
(workflowInstanceId, elementDetails, resultMessages) =>
{
resultMessages.Add(new NotificationMessage("An Error Occured!", MessageSeverity.Error));
});
Or the more generic interface
mockWebApiBusinessObject
.Setup(m => m.UpdateWorkflowInstanceState(It.IsAny<Guid>(), It.IsAny<WorkflowElementInstance>(), It.IsAny<IList<NotificationMessage>>()))
.Callback<Guid, WorkflowElementInstance, IList<NotificationMessage>>(
(workflowInstanceId, elementDetails, resultMessages) =>
{
resultMessages.Add(new NotificationMessage("An Error Occured!", MessageSeverity.Error));
});
You should also take some time and review Moq Quickstart to get a better understanding of how to use the mocking framework.
Please consider updating at minor places in your unit test.
Add before mocking IWebApiBusinessObject object:
List<NotificationMessage> messages = new List<NotificationMessage>();
Additionally, update Callback :
var mock = new Mock<IWebApiBusinessObject>();
mock.
Setup(m => m.UpdateWorkflowInstanceState(It.IsNotNull<Guid>(), It.IsNotNull<WorkflowElementInstance>(),It.IsAny<List<NotificationMessage>>() )).
Callback(() =>
{
messages.Add(new NotificationMessage("error msg", MessageSeverity.Severe));
messages.Add(new NotificationMessage("Ignore Message", MessageSeverity.Normal)); // this is optional... u can remove it if u want.
});
And need to update the source code method UpdateWorkflowElement(WorkflowElementModel model) to
UpdateWorkflowElement(WorkflowElementModel model, List<NotificationMessage> messages);
Consider changes in unit test code calling UpdateWorkflowElement to
var result = controller.UpdateWorkflowElement(workflowElementModel, messages);
If I have understood your UpdateWorkflowInstanceState() method correctly,
then you are using IWebApiBusinessObject to call UpdateWorkflowInstanceState( , , ) method.
When UpdateWorkflowInstanceState( , , ) executes during unit testing, it fires the Callback in your unit test and adds messages in list of NotificationMessage.

Unit testing Web API Controller: Error fetching result

I'm new to unit testing in ASP.NET so please forgive my ignorance on this. I'm trying to test my controller.
This is the function in my controller which I'm testing:
public IHttpActionResult GetCustId(string name)
{
var c_id = db.Customer.Where(s => (s.c_Name == name));
if (c_id == null)
{
return null;
}
return Ok(c_id);
}
And this is my unit test code:
public void GetName_ShouldReturnCorrectId()
{
var context = new TestSContext();
context.Customers.Add(new Customer { c_ID = 1, c_Name = "jonny"});
var controller = new CustomerController(context);
var result = controller.GetCustId("Johnny") as OkNegotiatedContentResult<Customer>; //ISSUE: Result is always NULL
Assert.IsNotNull(result);
Assert.AreEqual(1, result.Content.c_ID);
}
The issue is here:
var result = controller.GetServiceId("Johnny") as OkNegotiatedContentResult<Customer>
because it is always returning NULL.
BUT... If I use just this:
var result = controller.GetCustId("Johnny");
Then the result is not null. And the first assert passes.
But I can't use it because I'm not sure how to check the second assert statement without using result.Content. I'm really not sure what are the best practices to be testing in my case.
Appreciate any help.
You are trying to find "Johnny" (with 'h') when you have put "jonny" into your mock context thus method always returns null due to your if statement
if (c_id == null)
{
return null;
}
Adding to #nizzik's answer, which is correct based on your example, to avoid simple mistakes like that you should store your values in variables and reuse them to make sure that they are as intended.
public void GetName_ShouldReturnCorrectId() {
//Arrange
var name = "Johnny";
var expectedId = 1;
var context = new TestSContext();
context.Customers.Add(new Customer { c_ID = expectedId, c_Name = name});
var controller = new CustomerController(context);
//Act
var result = controller.GetCustId(name) as OkNegotiatedContentResult<Customer>;
//Assert
Assert.IsNotNull(result);
Assert.AreEqual(expectedId, result.Content.c_ID);
}
That way you can change any one of them and the test should execute as expected.

How to UnitTest a Function in a mocked method

How can I test the DeleteAppointmentById here?
Func<IDataAdapterRW, IEnumerable<uint>> function = db => DeleteAppointmentById(db, appointmentId);
return _dataContextProvider.GetContextRW().Run(function);
_dataContextProvider is mocked with moq. If I run the test it never enters DeleteAppointmentById of course
The method to test:
public IEnumerable<uint> DeleteAppointment(uint appointmentId)
{
Func<IDataAdapterRW, IEnumerable<uint>> function = db => DeleteAppointmentById(db, appointmentId);
return _dataContextProvider.GetContextRW().Run(function);
}
DeleteAppointmentById is the inner method (private) I am really interested in.
my test:
[Test]
public void DeleteAppointment_Valid_DeletedRecordId()
{
//Setup
var dbContextMock = new Mock<IDataContextProvider>();
var dataAdapterMock = new Mock<IDataContext<IDataAdapterRW>>();
dbContextMock.Setup(d => d.GetContextRW())
.Returns(dataAdapterMock.Object);
dataAdapterMock.Setup(a => a.Run(It.IsAny<Action<IDataAdapterRW>>()));
var calendarService = new CalendarService(dbContextMock.Object);
//Run
var result = calendarService.DeleteAppointment(1);
//Assert
Assert.AreEqual(1, result);
}
You can access the result of the Func passed as parameter in Run method, and to Assert the result like below.
Why to return the result? Because it's a mock and don't know how Run method is behaving.
[Test]
public void DeleteAppointment_Valid_DeletedRecordId()
{
//Setup
var dbContextMock = new Mock<IDataContextProvider>();
var dataAdapterMock = new Mock<IDataContext<IDataAdapterRW>>();
dbContextMock.Setup(d => d.GetContextRW())
.Returns(dataAdapterMock.Object);
dataAdapterMock.Setup(a => a.Run(It.IsAny<Func<IDataAdapterRW, IEnumerable<uint>>>()))
.Returns((Func<IDataAdapterRW, IEnumerable<uint>> func) => { return func(dataAdapterMock.Object);}); // configure the mock to return the list
var calendarService = new CalendarService(dbContextMock.Object);
//Run
int id = 1;
var result = calendarService.DeleteAppointment(id);
//Assert
var isInList = result.Contains(id); // verify the result if contains the
Assert.AreEqual(isInList, true);
}
Unit tests tend to take the following structure:
Arrange: set up the context. In this case, you'd probably create an appointment and save it to the database.
Act: call the unit you're testing. In this case, DeleteAppointmentById(db, appointment).
Assert: check if side effects and returns were correct. In this case, you may attempt to load this appointment from the database, and assert that you were unable (because it should have been deleted).

Categories