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).
Related
I have the following function that I am trying to put under unit test
public MessageListDto GetMessageList(SimpleSearchCriteria criteria)
{
var messages = _repository.GetMessages(criteria, out int total);
return new MessageListDto(messages, total);
}
and the following is my test so far, in which I am able to determine that _repository.GetMessages is call with the correct parameters.
However, how do I test that the second line is tested properly, I need to test that
A new object of type MessageListDto is constructed with the two parameters returned from the line above
the newly constructed object is returned
[Test]
public void Test1()
{
int total = 10;
var searchCriteria = new SimpleSearchCriteria();
var mockRepo = new Mock<IMessageRepository>();
var messageService = new MessageService(mockRepo.Object);
messageService.GetMessageList(searchCriteria);
mockRepo.Verify(r => r.GetMessages(searchCriteria, out total), Times.Once);
mockRepo.Verity ??????????
}
As we have discussed in the comment section your goal is to test the returned messages is passed to the dto's constructor without any modification.
With your current code you can't do that because you are creating the DTO explicitly inside your method. So, you can't replace it with a spy.
Just to clarify some terminologies:
Dummy: simple code that returns bogus data
Fake: a working alternative which can take shortcuts
Stub: custom logic with predefined data
Mock: custom logic with expectations (interactive stub)
Shim: custom logic at run-time
Spy: interceptors to record calls
To be able to capture the arguments of the MessageListDto constructor call you need to introduce an other layer between your GetMessageList method and the constructor. (In other words indirection)
For the sake of simplicity let me assume that IMessageRepository's GetMessages returns a string array.
So, you can introduce an interface like this:
public interface IDtoProvider
{
public MessageListDto CreateMessageList(string[] messages, int total)
=> new MessageListDto(messages, total);
}
Here I have used C# 8's interface default implementation feature
It can be further shortened with C# 9's target-typed new expression feature
If you are using older C# version then you need to separate the interface and the default implementation from each other
Now lets amend your MessageService to receive a IDtoProvider instance via its constructor
class MessageService
{
private readonly IMessageRepository _repository;
private readonly IDtoProvider _dtoProvider;
public MessageService(IMessageRepository repository, IDtoProvider dtoProvider)
=> (_repository, _dtoProvider) = (repository, dtoProvider);
public MessageListDto GetMessageList(SimpleSearchCriteria criteria)
{
var messages = _repository.GetMessages(criteria, out int total);
return _dtoProvider.CreateMessageList(messages, total);
}
...
}
Here I've took advantage of ValueTuple's deconstruct capability
With these in our hand we can write a unit test like this:
//Arrange - Repo
string[] messages = new[] { "OnlyElement" };
int total = 10;
var mockRepo = new Mock<IMessageRepository>();
mockRepo
.Setup(repo => repo.GetMessages(It.IsAny<SimpleSearchCriteria>(), out total))
.Returns(messages);
//Arrange - Provider
var dto = new MessageListDto(messages, total);
string[] messagesArgument = null;
int totalArgument = -1;
var mockProvider = new Mock<IDtoProvider>();
mockProvider
.Setup(provider => provider.CreateMessageList(It.IsAny<string[]>(), It.IsAny<int>()))
.Callback<string[], int>((messages, total) => (messagesArgument, totalArgument) = (messages, total))
.Returns(dto);
//Arrange - SUT
var searchCriteria = new SimpleSearchCriteria();
var sut = new MessageService(mockRepo.Object, mockProvider.Object);
//Act
sut.GetMessageList(searchCriteria);
//Assert - Repo
mockRepo.Verify(r => r.GetMessages(searchCriteria, out total), Times.Once);
//Assert - Provider
Assert.Equal(messages, messagesArgument);
Assert.Equal(total, totalArgument);
I've defined how should the IMessageRepository mock behave
I've defined how should the IDtoProvider mock behave
2.1 I've used here the Callback method to capture the calling argument
2.2 If you perform multiple calls against your mocked method then please consider to use Capture.In
I've instantiated a MessageService (which is our system under test) with the mock objects
I've called the GetMessageList inside the Act phase
I've made assertion against the repo mock call
I've made assertion against the calling parameters of the CreateMessageList
6.1 Here I have used xunit's assertion
The first step is to setup the MessageService mock, so that it returns something deterministic and then in the second step you verify that that has been used to construct your MessageListDto.
[Test]
public void Test1()
{
// arrange
int total = 10;
var searchCriteria = new SimpleSearchCriteria();
var messages = new [] {"message1", "message2"} // or similar
var mockRepo = new Mock<IMessageRepository>();
// or similar, I am not quite certain as to the specific syntax. Especially wrt. out parameters. Check the documentation.
mockRepo.Setup(x => x.GetMessages(It.IsAny<SimpleSearchCriteria>(), It.IsAny<int>())).Returns(messages);
var messageService = new MessageService(mockRepo.Object);
// act
var result = messageService.GetMessageList(searchCriteria);
// assert
mockRepo.Verify(r => r.GetMessages(searchCriteria, out total), Times.Once);
// or similar; here you might want to check out FluentAssertions as #Peter Csala suggested
Assert.Equal(result.Messages, messages);
}
What's missing from previous answers is that whenever possible, you should set up the mocked method with the exact parameters, that you expect it to receive. In other words set up the method with concrete values instead of It.IsAny<>(). In such case you won't have to verify the method later at all. (Unless it's critical to test, how many times a method is called). Simply, if mocked GetMessages receives different arguments than expected, it will return null, set total to 0 and your test will fail. Having the mocked methods set up properly, you can now focus on verifying what GetMessageList returns, which is the purpose of this unit test.
[Test]
public void Test1()
{
int total = 10;
var messages = new[] {new Message()};
var searchCriteria = new SimpleSearchCriteria();
var mockRepo = new Mock<IMessageRepository>();
mockRepo.Setup(_ => _.GetMessages(searchCriteria, out total))
.Returns(messages);
var messageService = new MessageService(mockRepo.Object);
var dto = messageService.GetMessageList(searchCriteria);
Assert.AreSame(messages, dto.Messages);
Assert.AreEqual(total, dto.Total);
}
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?
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
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.
is it possible to assert whether a method has been called? I'm testing the following method and I want to assert that the _tokenManager.GetToken() has been called. I just want to know if the method has been called as the method does not return a value. I am using Moq.
Thanks,
Code snippet
public void Subscribe(string code, string emailAddress, string columnKey)
{
// Request authentication token
var token = _tokenManager.GetToken(code, false);
if (!_tokenValidator.Validate(token))
{
// Token has expired or invalid - refresh the token
token = _tokenManager.GetToken(code, true);
}
// Subscribe email
_silverpopRepository.Subscribe(token.AccessToken, emailAddress, columnKey);
}
You should mock TokenManager and TokenValidator, and then create two unit test cases:
Case 1: token is validated and GetToken is called exactly once
Case 2: token is not validated and GetToken is called exactly twice
Case 1:
[Test]
public void Subscribe_TokenIsValidated_GetTokenIsCalledOnce()
{
// Arrange:
var tokenManagerMock = Mock.Of<TokenManager>();
var tokenValidatorMock = Mock.Of<TokenValidator>(x =>
x.Validate(It.IsAny<Token>()) == true);
var subscriber = new Subscriber
{
TokenManager = tokenManagerMock,
TokenValidator = tokenValidatorMock
};
// Act:
subscriber.Subscribe(It.IsAny<string>(), It.IsAny<string>(),
It.IsAny<string>());
// Assert:
Mock.Get(tokenManagerMock).Verify(x =>
x.GetToken(It.IsAny<string>(), It.IsAny<bool>()), Times.Once);
}
Case 2:
[Test]
public void Subscribe_TokenIsExpiredOrInvalid_GetTokenIsCalledTwice()
{
// Arrange:
var tokenManagerMock = Mock.Of<TokenManager>();
var tokenValidatorMock = Mock.Of<TokenValidator>(x =>
x.Validate(It.IsAny<Token>()) == false);
var subscriber = new Subscriber
{
TokenManager = tokenManagerMock,
TokenValidator = tokenValidatorMock
};
// Act:
subscriber.Subscribe(It.IsAny<string>(), It.IsAny<string>(),
It.IsAny<string>());
// Assert:
Mock.Get(tokenManagerMock).Verify(x =>
x.GetToken(It.IsAny<string>(), It.IsAny<bool>()), Times.Exactly(2));
}
Alternatively, you can create an unit test without mocking TokenValidator and verify if GetToken() has been called at least once. However, creating two cases as in the first example is preferred as we are testing all code paths.
// Arrange:
var tokenManagerMock = Mock.Of<TokenManager>();
var subscriber = new Subscriber {TokenManager = tokenManagerMock};
// Act:
subscriber.Subscribe(It.IsAny<string>(),
It.IsAny<string>(),
It.IsAny<string>());
// Assert:
Mock.Get(tokenManagerMock).Verify(x =>
x.GetToken(It.IsAny<string>(), It.IsAny<bool>()), Times.AtLeastOnce);
Read more about verification in Moq at:
Moq quick start at official website
Verifying the Number of Calls to a Mocked Method at BlackWasp
You can verify using MOQ using the Verify method. Like this:
var tokenManagerMock = new Mock<ITokenManager>();
var sut = new WhateverItIsCalled(tokenManagerMock.Object);
sut.Subscribe("ssss", "example#example.com", "XXX");
tokenManagerMock.Verify(m => m.GetToken(It.Is<string>(c => c == "ssss", It.Is<bool>(x => x == false)), Times.Once);
You need to be able to pass the token manager into your system under test somehow. Usually via the ctor or maybe a property.
I would suggest you use something like AutoFixture to remove the ugliness that is "ssss" and make things a bit more DRY.
You may need to make the token manager mock return something appropriate too that will pass the validation. Something like this:
var tokenManagerMock = new Mock<ITokenManager>();
tokenManagerMock.Setup(m => m.GetToken(It.Is<string>(x => x == "ssss", It.IsAny<bool>()).Returns("XXXXXX");