Benn trying to test a service layer method which returns a simple IList using RhinoMocks 3.6
[TestMethod]
public void GetItems_Returns_ActionItemsList()
{
// arrange
var mockRepository = MockRepository.GenerateMock<IActionItemRepository>();
mockRepository.Stub(s => s.Select()).Return(GetFakeActionItems());
var service = new ActionItemQueueService(mockRepository);
// act
var actual = service.GetItems();
mockRepository.VerifyAllExpectations();
// assert
Assert.IsInstanceOfType(actual, typeof(IList<ActionItem>));
}
Real simplle right?
The GetFakeActionItems method for reference;
internal IQueryable<ActionItem> GetFakeActionItems()
{
return new List<ActionItem> {
new ActionItem{
Id = 5,
ClientName = "Bank of American Corporation",
ActionNeeded = RequiredAction.Change,
RecordIndicator = "ROI",
RequestDate = DateTime.Now.AddDays(-3)
}
} as IQueryable<ActionItem>;
}
Here is the class and method under test...
public class ActionItemQueueService : IActionQueueService
{
private readonly IActionItemRepository _actionItemRepository;
public ActionItemQueueService(IActionItemRepository actionItemRepository)
{
_actionItemRepository = actionItemRepository;
if (_actionItemRepository == null)
{
throw new ArgumentNullException("ActionItemRepository");
}
}
public IList<Model.ActionItem> GetItems()
{
return _actionItemRepository.Select().ToList<Model.ActionItem>();
}
}
Nothing wild....
When I run my test, I Get an ArgumentNullException when the GetItems() method is called when _actionItemRepository.Select() fires. Value cannot be null.
Parameter name: source.
Confused and perplexed wondering if anyone has any insight into what I am missing.
Many thanks!
I believe the problem is that you are taking your List<ActionItem> and performing "as IQueryable<ActionItem>" on it in your GetFakeActionItems method. This returns null as it is not a valid conversion.
Thus, when your mock ActionItemRepository runs the stubbed out Select() it returns null (via GetFakeActionItems), which causes the subsequent ToList<Model.ActionItem>() to go down in flames with the ArgumentNullException.
What you actually want to do in your GetFakeActionItems is:
myList.AsQueryable()
Related
I am trying to mock my service's create method like this in the class constructor:
serviceMock.Setup(p => p.AddClinic(GetTestClinicModel()))
.Returns(GetTestClinic());
Mock Model and Mock Entity
private CreateClinicBindingModel GetTestClinicModel()
{
return new CreateClinicBindingModel()
{
Name = "Clinic-3"
};
}
private Clinic GetTestClinic()
{
return new Clinic()
{
Id = 3,
Name = "Clinic-3"
};
}
Test Method
[Fact]
public void Add_ValidObjectPassed_ReturnsCreatedResponse()
{
// Act
var createdResponse = controller.Add(GetTestClinicModel());
// Assert
Assert.IsType<CreatedAtActionResult>(createdResponse);
}
Controller Add Method
[HttpPost("create")]
public IActionResult Add(CreateClinicBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest();
}
var entity = _service.AddClinic(model);
return Created(entity);
}
So my problem is test getting failure and when I debug _service.AddClinic() method it returns null.
The mock service does not return the expected Entity (Clinic).
How can I solve this?
The issue is that the setup expects the specific instance created when GetTestClinicModel() is invoked.
However that same instance is not used when exercising the test as a totally new instance is created when GetTestClinicModel() is invoked again.
Thus the mock will return null since there are separate instances.
Consider changing the setup to use an argument matcher like It.Is<T>()
serviceMock
.Setup(_ => _.AddClinic(It.Is<CreateClinicBindingModel>(m => m.Name == "Clinic-3")))
.Returns(GetTestClinic());
The above setup tells the mock to behave as expected when it gets an instance that matches the provided predicate
I'm having a difficult time trying to understand how to appropriately return mocked data from a simulated database call in a unit test.
Here's an example method I want to unit test (GetBuildings):
public class BuildingService : IBuildingService {
public IQueryable<Building> GetBuildings(int propertyId)
{
IQueryable<Building> buildings;
// Execution path for potential exception thrown
// if (...) throw new SpecialException();
// Another execution path...
// if (...) ...
using (var context = DataContext.Instance())
{
var Params = new List<SqlParameter>
{
new SqlParameter("#PropertyId", propertyId)
};
// I need to return mocked data here...
buildings = context
.ExecuteQuery<Building>(System.Data.CommandType.StoredProcedure, "dbo.Building_List", Params.ToArray<object>())
.AsQueryable();
}
return buildings;
}
}
So GetBuildings calls a stored procedure.
So I need to mock the DataContext, that of which I can override and set a testable instance. So what happens here is, in the above example DataContext.Instance() does return the mocked object.
[TestFixture]
public class BuildingServiceTests
{
private Mock<IDataContext> _mockDataContext;
[SetUp]
public void Setup() {
_mockDataContext = new Mock<IDataContext>();
}
[TearDown]
public void TearDown() {
...
}
[Test]
public void SomeTestName() {
_mockDataContext.Setup(r =>
r.ExecuteQuery<Building>(CommandType.StoredProcedure, "someSproc"))
.Returns(new List<Building>() { new Building() { BuildingId = 1, Title = "1" }}.AsQueryable());
DataContext.SetTestableInstance(_mockDataContext.Object);
var builings = BuildingService.GetBuildings(1, 1);
// Assert...
}
Please ignore some of the parameters, like propertyId. I've stripped those out and simplified this all. I simply can't get the ExecuteQuery method to return any data.
All other simple peta-poco type methods I can mock without issue (i.e. Get, Insert, Delete).
Update
DataContext.Instance returns the active instance of the DataContext class, if exists, and if not exists, returns a new one. So the method of test under question returns the mocked instance.
Do not mock DataContext. Because mocking DataContext will produce tests tightly coupled to the implementation details of DataContext. And you will be forced to change tests for every change in the code even behavior will remain same.
Instead introduce a "DataService" interface and mock it in the tests for BuildingService.
public interface IDataService
{
IEnumerable<Building> GetBuildings(int propertyId)
}
Then, you can tests implementation of IDataService agains real database as part of integration tests or tests it agains database in memory.
If you can test with "InMemory" database (EF Core or Sqlite) - then even better -> write tests for BuildingService against actual implementation of DataContext.
In tests you should mock only external resources (web service, file system or database) or only resources which makes tests slow.
Not mocking other dependencies will save you time and give freedom while you refactoring your codebase.
After update:
Based on the updated question, where BuildingService have some execution path - you can still testing BuildingService and abstract data related logic to the IDataService.
For example below is BuildingService class
public class BuildingService
{
private readonly IDataService _dataService;
public BuildingService(IDataService dataService)
{
_dataService = dataService;
}
public IEnumerable<Building> GetBuildings(int propertyId)
{
if (propertyId < 0)
{
throw new ArgumentException("Negative id not allowed");
}
if (propertyId == 0)
{
return Enumerable.Empty<Building>();
}
return _myDataService.GetBuildingsOfProperty(int propertyId);
}
}
In tests you will create a mock for IDataService and pass it to the constructor of BuildingService
var fakeDataService = new Mock<IDataContext>();
var serviceUnderTest = new BuildingService(fakeDataService);
Then you will have tests for:
"Should throw exception when property Id is negative"
"Should return empty collection when property Id equals zero"
"Should return collection of expected buildings when valid property Id is given"
For last test case you will mock IDataService to return expected building only when correct propertyId is given to _dataService.GetBuildingsOfProperty method
In order for the mock to return data is needs to be set up to behave as expected given a provided input.
currently in the method under test it is being called like this
buildings = context
.ExecuteQuery<Building>(System.Data.CommandType.StoredProcedure, "dbo.Building_List", Params.ToArray<object>())
.AsQueryable();
Yet in the test the mock context is being setup like
_mockDataContext.Setup(r =>
r.ExecuteQuery<Building>(CommandType.StoredProcedure, "someSproc"))
.Returns(new List<Building>() { new Building() { BuildingId = 1, Title = "1" }}.AsQueryable());
Note what the mock is told to expect as parameters.
The mock will only behave as expected when provided with those parameters. Otherwise it will return null.
Consider the following example of how the test can be exercised based on the code provided in the original question.
[Test]
public void SomeTestName() {
//Arrange
var expected = new List<Building>() { new Building() { BuildingId = 1, Title = "1" }}.AsQueryable();
_mockDataContext
.Setup(_ => _.ExecuteQuery<Building>(CommandType.StoredProcedure, It.IsAny<string>(), It.IsAny<object[]>()))
.Returns(expected);
DataContext.SetTestableInstance(_mockDataContext.Object);
var subject = new BuildingService();
//Act
var actual = subject.GetBuildings(1);
// Assert...
CollectionAssert.AreEquivalent(expected, actual);
}
That said, the current design of the system under test is tightly coupled to a static dependency which is a code smell and makes the current design follow some bad practices.
The static DataContext which is currently being used as a factory should be refactored as such,
public interface IDataContextFactory {
IDataContext CreateInstance();
}
and explicitly injected into dependent classes instead of calling the static factory method
public class BuildingService : IBuildingService {
private readonly IDataContextFactory factory;
public BuildingService(IDataContextFactory factory) {
this.factory = factory
}
public IQueryable<Building> GetBuildings(int propertyId) {
IQueryable<Building> buildings;
using (var context = factory.CreateInstance()) {
var Params = new List<SqlParameter> {
new SqlParameter("#PropertyId", propertyId)
};
buildings = context
.ExecuteQuery<Building>(System.Data.CommandType.StoredProcedure, "dbo.Building_List", Params.ToArray<object>())
.AsQueryable();
}
return buildings;
}
}
This will allow for a proper mock to be created in injected into the subject under test without using a static workaround hack.
[Test]
public void SomeTestName() {
//Arrange
var expected = new List<Building>() { new Building() { BuildingId = 1, Title = "1" }}.AsQueryable();
_mockDataContext
.Setup(_ => _.ExecuteQuery<Building>(CommandType.StoredProcedure, It.IsAny<string>(), It.IsAny<object[]>()))
.Returns(expected);
var factoryMock = new Mock<IDataContextFactory>();
factoryMock
.Setup(_ => _.CreateInstance())
.Returns(_mockDataContext.Object);
var subject = new BuildingService(factoryMock.Object);
//Act
var actual = subject.GetBuildings(1);
// Assert...
CollectionAssert.AreEquivalent(expected, actual);
}
I have a unit test I am checking whether a method is called once or not so I attempted this way:-
This is my Mock of ILicenseManagerService and I am passing its object through constructor.
public Mock<ILicenseManagerService> LicenseManagerService { get { return SetLicenseManagerServiceMock(); } }
private Mock<ILicenseManagerService> SetLicenseManagerServiceMock()
{
var licencemangerservicemock = new Mock<ILicenseManagerService>();
licencemangerservicemock.Setup(m => m.LoadProductLicenses()).Returns(ListOfProductLicense).Verifiable();
return licencemangerservicemock;
}
public static async Task<IEnumerable<IProductLicense>> ListOfProductLicense()
{
var datetimeoffset = new DateTimeOffset(DateTime.Now);
var lst = new List<IProductLicense>
{
GetProductLicense(true, datetimeoffset, false, "1"),
GetProductLicense(true, datetimeoffset, false, "2"),
GetProductLicense(true, datetimeoffset, true, "3")
};
return lst;
}
I am using this mock object to set _licenseManagerService and calling the LoadProductLicenses() in method under test. like this. licences are coming fine.
var licenses = (await _licenseManagerService.LoadProductLicenses()).ToList();
My attempt for verify the call to this method -
LicenseManagerService.Verify(m => m.LoadProductLicenses(),Times.Once);
But when I run my unit test, an exception coming that say method is not invoked at all.
Where I am doing wrong ?
EDIT #dacastro I am invoking the same mock here is my unit test.
[TestMethod]
[TestCategory("InApp-InAppStore")]
public async Task return_products_from_web_when_cache_is_empty()
{
// this class basically for setting up external dependencies
// Like - LicenceManagerService in context, i am using this mock only no new mock.
var inAppMock = new InAppMock ();
// object of Class under test- I used static method for passing external
//services for easy to change
var inAppStore = StaticMethods.GetInAppStore(inAppMock);
// method is called in this method
var result = await inAppStore.LoadProductsFromCacheOrWeb();
// like you can see using the same inAppMock object and same LicenseManagerService
inAppMock.LicenseManagerService.Verify(m => m.LoadProductLicenses(),Times.Once);
}
LicenseManagerService.Verify(m => m.LoadProductLicenses(),Times.Once);
By calling the LicenseManagerService property, you're creating a new mock object. Naturally, no invocations have ever been performed on this instance.
You should change this property's implementation to return the same instance every time it is called.
Scenario: I am learning how to unit test. Currently am working on tests for an mvc action method with nUnit and FakeItEasy. I have a test to verify that the method throws an exception if passed an id that doesn't exist. The action method calls a repository wrapper method for .Single(), which will throw an exception if nothing is found. This is good.
In my test, I do the following:
Create fake IRepository using FakeItEasy
Create test data
Configure .Single() wrapper method to get data from my test data
Problem: I am having issues testing this. The problem is that when passed an invalid id, an exception is thrown right in the configuration code for the fake repository, instead of in the action method itself. The reason why is obvious. The configuration code is ran before the action method gets executed, and the configuration code calls .Single() on the test data... which (intentionally of course) does not contain the invalid id. So it throws an exception right then and there, and never even makes it to the action method. What I am not sure about, is how to get around this. The exception needs to be thrown inside the action method. I don't know how to configure the return value in a way that avoids this conundrum.
Code:
Controller Code
public ViewResult Details(int id)
{
var dbPart = _repository
.GetSingleRecord<Part>(x => x.PartID == id);
var viewmodel = new DetailsViewModel()
{
PartID = dbPart.PartID
};
return View(viewmodel);
}
Test Code
[TestFixtureSetUp]
public void TestFixtureSetUp()
{
// Create a fake PartID that exists
partID_that_exists = 1;
// Create a fake PartID that doesn't exist
partID_that_doesnt_exist = -100;
}
[Test]
public void an_exception_is_thrown_if_the_part_doesnt_exist()
{
// Arrange
FakeRepository.FakePartID = partID_that_doesnt_exist;
_fakeRepository = FakeRepository.Create();
_controller = new PartController(_fakeRepository);
// Act & Assert
Assert.Throws<InvalidOperationException>(() =>
_controller.Details(partID_that_doesnt_exist));
}
Fake Repository Code
public class FakeRepository
{
public static int? FakePartID { get; set; }
public static IBasicRepository Create()
{
// Create fake repository
var fakeRepository = A.Fake<IBasicRepository>();
// Create fake test data
var fakeParts = new List<Part>()
{
new Part()
{
PartID = 1, PartDesc = "Fake Part 1"
},
new Part()
{
PartID = 2, PartDesc = "Fake Part 2"
}
};
// Configure fake repository to return fake data
A.CallTo(() => fakeRepository.GetAllRecords<Part>())
.Returns(fakeParts);
if (FakePartID.HasValue)
{
/* BELOW CODE IS THE PROBLEM */
A.CallTo(fakeRepository)
.Where(call => call.Method.Name == "GetSingleRecord")
.WithReturnType<Part>()
.Returns(fakeParts.Single(x => x.PartID == FakePartID));
}
// Return the newly created & configured fakeRepository
return fakeRepository;
}
}
I figured it out. I needed to use ReturnsLazily() instead of Returns().
ReturnsLazily delays setting the method's return values until the method is actually called, instead of setting them when the method's configuration code is executed.
New, Working Code:
A.CallTo(fakeRepository)
.Where(call => call.Method.Name == "GetSingleRecord")
.WithReturnType<Part>()
.ReturnsLazily(() => fakeParts
.Single(x => x.PartID == FakePartID));
[unit testing newbie] [c#]
Consider the following scenario:
I'm using Silverlight and calling a WCF service. Silverlight can only call WCF services asynchronously. I build a wrapper around the WCF service so that I can work with Action parameters. (makes the client code a lot cleaner).
So I have an async service that retrieves meeting rooms.
public interface IMeetingRoomService
{
void GetRooms(Action<List<MeetingRoom>> result);
}
Turning GetRooms into List<MeetingRoom> GetRooms() is not an option.
I want to use this service in a ViewModel to set a public property called Rooms.
public class SomeViewModel
{
private readonly IMeetingRoomService _meetingRoomService;
public List<MeetingRoom> Rooms { get; set; }
public SomeViewModel(IMeetingRoomService meetingRoomService)
{
this._meetingRoomService = meetingRoomService;
}
public void GetRooms()
{
// Code that calls the service and sets this.Rooms
_meetingRoomService.GetRooms(result => Rooms = result);
}
}
I want to unit test the implementation of SomeViewModel.GetRooms().
(For this question I quickly wrote the implementation but I'm actually trying to use TDD.)
How do I finish this test?
I'm using NUnit and Moq.
[Test]
public void GetRooms_ShouldSetRooms()
{
var theRooms = new List<MeetingRoom>
{
new MeetingRoom(1, "some room"),
new MeetingRoom(2, "some other room"),
};
var meetingRoomService = new Mock<IMeetingRoomService>();
//How do I setup meetingRoomService so that it gives theRooms in the Action??
var viewModel = new SomeViewModel(meetingRoomService.Object);
viewModel.GetRooms();
Assert.AreEqual(theRooms, viewModel .Rooms);
}
EDIT:
Solution
Read Stephane's answer first.
This is the Test code I ended up writing thanks to stephane's answer:
[Test]
public void GetRooms_ShouldSetRooms()
{
var meetingRoomService = new Mock<IMeetingRoomService>();
var shell = new ShellViewModel(meetingRoomService.Object);
var theRooms = new List<MeetingRoom>
{
new MeetingRoom(1, "some room"),
new MeetingRoom(2, "some other room"),
};
meetingRoomService
.Setup(service => service.GetRooms(It.IsAny<Action<List<MeetingRoom>>>()))
.Callback((Action<List<MeetingRoom>> action) => action(theRooms));
shell.GetRooms();
Assert.AreEqual(theRooms, shell.Rooms);
}
Here is some pseudo code, I haven't run it. But I think that's what you want.
SetupCallback is what you are interested in.
For all the calls to _meetingRoomServiceFake.GetRooms, simply set the _getRoomsCallback to the parameter passed in.
You now have a reference to the callback that you are passing in your viewmodel, and you can call it with whatever list of MeetingRooms you want to test it.
So you can test your asynchronous code almost the same way as synchronous code. it's just a bit more ceremony to setup the fake.
Action<List<MeetingRoom>> _getRoomsCallback = null;
IMeetingRoomService _meetingRoomServiceFake;
private void SetupCallback()
{
Mock.Get(_meetingRoomServiceFake)
.Setup(f => f.GetRooms(It.IsAny<Action<List<MeetingRoom>>>()))
.Callback((Action<List<MeetingRoom>> cb) => _getRoomsCallback= cb);
}
[Setup]
public void Setup()
{
_meetingRoomServiceFake = Mock.Of<IMeetingRoomService>();
SetupCallback();
}
[Test]
public void Test()
{
var viewModel = new SomeViewModel(_meetingRoomServiceFake)
//in there the mock gets called and sets the _getRoomsCallback field.
viewModel.GetRooms();
var theRooms = new List<MeetingRoom>
{
new MeetingRoom(1, "some room"),
new MeetingRoom(2, "some other room"),
};
//this will call whatever was passed as callback in your viewModel.
_getRoomsCallback(theRooms);
}
You could use an AutoResetEvent to handle async calls.
Just initialize it as unset and configure your mock service to set it in the callback.
(IE:
var mockService = new Mock();
mockService.SetUp(x => x.MyMethod()).Returns(someStuff).Callback(() => handle.Set());
)
After that I use hadle.WaitOne(1000) to check if it was called. (IMHO 1000 miliseconds are more than enough to run the async code).
Sorry: This was supposed to go as a reply to the post above... I can't for the life of me figure out how to reply :)