I am experiencing some weird behavior using MOQ in my unit tests:
Given the following test:
[Fact]
public void ShoppingCart_ShouldIncrementQuantity_WhenAddingDuplicateItem()
{
var cart = new ShoppingCart();
var item1 = GetMockItem("Test");
var item2 = GetMockItem("Test", quantity: 2);
cart.AddItem(item1.Object);
cart.AddItem(item2.Object);
cart.Items.Single(x => x.Sku == "Test").Quantity
.Should().Be(3);
}
private Mock<IShoppingCartItem> GetMockItem(string sku, decimal price = 10, int quantity = 1)
{
var mock = new Mock<IShoppingCartItem>();
mock.Setup(x => x.Sku).Returns(sku);
mock.Setup(x => x.Price).Returns(price);
mock.Setup(x => x.Quantity).Returns(quantity);
return mock;
}
And this is the code under test:
public void AddItem(IShoppingCartItem item)
{
Enforce.ArgumentNotNull(item, "item");
var existingItem = this.Items.SingleOrDefault(x => x.Sku == item.Sku);
if (existingItem != null)
{
existingItem.Quantity += item.Quantity;
}
else
{
this.Items.Add(item);
}
}
I am getting this result: Test 'Titan.Tests.ShoppingCartTests.ShoppingCart_ShouldIncrementQuantity_WhenAddingDuplicateItem' failed: Expected 3, but found 1.
I am baffled or I am just having a dumb moment!
The problem here is that you haven't told Moq what to do when the Quantity property is set.
By default, Moq doesn't just assume that all of your properties should be simple getter/setters. It's up to you to decide what to do with them.
You have a couple of options.
Use SetupAllProperties() to tell Moq to treat properties as simple getter/setters.
private Mock<IShoppingCartItem> GetMockItem(string sku, decimal price = 10, int quantity = 1)
{
var mock = new Mock<IShoppingCartItem>();
mock.SetupAllProperties();
// Set the properties like normal properties. Moq will do the right thing.
mock.Object.Sku = sku;
mock.Object.Price = price;
mock.Object.Quantity = quantity;
return mock;
}
Use SetupSet to handle the case where the Quantity property is set, and in its callback, re-setup the property getter, so that it returns the new value.
private Mock<IShoppingCartItem> GetMockItem(string sku, decimal price = 10, int quantity = 1)
{
var mock = new Mock<IShoppingCartItem>();
mock.Setup(x => x.Sku).Returns(sku);
mock.Setup(x => x.Price).Returns(price);
mock.Setup(x => x.Quantity).Returns(quantity);
// You can call Setups from within Setups
mock.SetupSet(x => x.Quantity).Callback(q => mock.Setup(x => x.Quantity).Returns(q));
return mock;
}
Alternately, you could also change your design so that you aren't modifying public properties.
The mocked property of the first item is set up to always return 1. It doesn't matter you add 2 to it then, it will always return 1.
Edit: your += is ignored because your cart stores mocked objects. The one that gets to the cart first is mocked to ALWAYs returns 1.
Related
I am writing unit tests for DocumentDBRepository but I got a null reference exception. I use Moq framework and XUnit.
Here's my methods in DocumentDBRepository class.
public class DocumentDBRepository<T> : IRepository<T> where T: class
{
private static string DatabaseId;
private static string CollectionId;
private static IDocumentClient client;
public DocumentDBRepository(IDocumentClient documentClient, string databaseId, string collectionId)
{
DatabaseId = databaseId;
CollectionId = collectionId;
client = documentClient;
CreateDatabaseIfNotExistsAsync().Wait();
CreateCollectionIfNotExistsAsync().Wait();
}
public async Task<IDocumentQuery<T>> GetQuery(Expression<Func<T, bool>> predicate)
{
try
{
IDocumentQuery<T> query = client.CreateDocumentQuery<T>(
UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId),
new FeedOptions { MaxItemCount = -1, EnableCrossPartitionQuery = true })
.Where(predicate)
.AsDocumentQuery();
return query;
}
catch (Exception e) {
throw;
}
}
public async Task<IEnumerable<T>> GetEntities(IDocumentQuery<T> query)
{
try
{
List<T> results = new List<T>();
while (query.HasMoreResults)
{
results.AddRange(await query.ExecuteNextAsync<T>());
}
return results;
}
catch (Exception e)
{
throw;
}
}
}
Here's my test code:
public interface IFakeDocumentQuery<T> : IDocumentQuery<T>, IOrderedQueryable<T>
{
}
[Fact]
public async virtual Task Test_GetBooksById()
{
var expected = new List<Book> {
new Book { ID = "123", Description = "HarryPotter"},
new Book { ID = "124", Description = "HarryPotter2"} };
var response = new FeedResponse<Book>(expected);
var mockDocumentQuery = new Mock<IFakeDocumentQuery<Book>>();
mockDocumentQuery.SetupSequence(_ => _.HasMoreResults)
.Returns(true)
.Returns(false);
mockDocumentQuery.Setup(_ => _.ExecuteNextAsync<Book>(It.IsAny<CancellationToken>()))
.ReturnsAsync(response);
var client = new Mock<IDocumentClient>();
client.Setup(_ => _.CreateDocumentQuery<Book>(It.IsAny<Uri>(), It.IsAny<FeedOptions>()))
.Returns(mockDocumentQuery.Object);
var documentsRepository = new DocumentDBRepository<Book>(client.Object, "123", "123");
//Act
var query = await documentsRepository.GetQuery(t => t != null);
var entities = await documentsRepository.GetEntities(query);
//Assert
if (entities != null)
{
entities.Should().BeEquivalentTo(expected);
}
}
Here's the error message after running the test method:
Message: System.NullReferenceException : Object reference not set to
an instance of an object.
When I stepped through the code, the error happens right after the the test code called GetQuery() method:
IDocumentQuery<T> query = client.CreateDocumentQuery<T>(
UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId),
new FeedOptions { MaxItemCount = -1, EnableCrossPartitionQuery = true })
.Where(predicate)
.AsDocumentQuery();
Here's my thought process: when I stepped through the entire code, I do not see any null variables. But in the 'response' variable from the second line of the test method, it does show a lot of the properties are null exception but result view shows the 'expected' variable.
My question is, is it because of the response variable that caused the null reference exception? Or somewhere else?
PS: Test code reference from here
I also tried turning on the Mock behavior to strict and saw this error message.
Message: System.AggregateException : One or more errors occurred.
(IDocumentClient.ReadDatabaseAsync(dbs/123, null) invocation failed
with mock behavior Strict. All invocations on the mock must have a
corresponding setup.)
---- Moq.MockException : IDocumentClient.ReadDatabaseAsync(dbs/123, null) invocation failed with mock behavior Strict. All invocations on
the mock must have a corresponding setup.
As suspected the problem is .Where(predicate). I ran a test with the provided example and removed the .Where clause and it executed to completion.
The fake interface inherits from both IOrderedQueryable and IDocumentQuery. The issue is that the Where is converting it back to a plain IEnumerable because of the List data source and the AsDocumentQuery is crapping out as it is expecting an IDocumentQuery
I am not a fan of tightly coupling to APIs I can't control. I would abstract my way around such implementation details for that very reason.
The work around involved having to provide a fake Linq IQueryProvider to bypass any queries and return a type that derives from IDocumentQuery so as to allow AsDocumentQuery to behave as intended.
But first I refactored GetEntities and made GetQuery private to stop the repository from being a leaky abstraction.
private IDocumentQuery<T> getQuery(Expression<Func<T, bool>> predicate) {
var uri = UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId);
var feedOptions = new FeedOptions { MaxItemCount = -1, EnableCrossPartitionQuery = true };
var queryable = client.CreateDocumentQuery<T>(uri, feedOptions);
IQueryable<T> filter = queryable.Where(predicate);
IDocumentQuery<T> query = filter.AsDocumentQuery();
return query;
}
public async Task<IEnumerable<T>> GetEntities(Expression<Func<T, bool>> predicate) {
try {
IDocumentQuery<T> query = getQuery(predicate);
var results = new List<T>();
while (query.HasMoreResults) {
results.AddRange(await query.ExecuteNextAsync<T>());
}
return results;
} catch (Exception e) {
throw;
}
}
Note that getQuery is not doing anything async so it should not be returning a Task<> anyway.
Next in the test the mocked IDocumentQuery was set up to allow the test to flow to completion. This was done by providing a mocked IQueryProvider the would return the mocked IDocumentQuery when Linq queries are invoked against it. (which was the cause of the problem to begin with)
public async virtual Task Test_GetBooksById() {
//Arrange
var id = "123";
Expression<Func<Book, bool>> predicate = t => t.ID == id;
var dataSource = new List<Book> {
new Book { ID = id, Description = "HarryPotter"},
new Book { ID = "124", Description = "HarryPotter2"}
}.AsQueryable();
var expected = dataSource.Where(predicate);
var response = new FeedResponse<Book>(expected);
var mockDocumentQuery = new Mock<IFakeDocumentQuery<Book>>();
mockDocumentQuery
.SetupSequence(_ => _.HasMoreResults)
.Returns(true)
.Returns(false);
mockDocumentQuery
.Setup(_ => _.ExecuteNextAsync<Book>(It.IsAny<CancellationToken>()))
.ReturnsAsync(response);
var provider = new Mock<IQueryProvider>();
provider
.Setup(_ => _.CreateQuery<Book>(It.IsAny<System.Linq.Expressions.Expression>()))
.Returns((Expression expression) => {
if (expression != null) {
dataSource = dataSource.Provider.CreateQuery<Book>(expression);
}
mockDocumentQuery.Object;
});
mockDocumentQuery.As<IQueryable<Book>>().Setup(x => x.Provider).Returns(provider.Object);
mockDocumentQuery.As<IQueryable<Book>>().Setup(x => x.Expression).Returns(() => dataSource.Expression);
mockDocumentQuery.As<IQueryable<Book>>().Setup(x => x.ElementType).Returns(() => dataSource.ElementType);
mockDocumentQuery.As<IQueryable<Book>>().Setup(x => x.GetEnumerator()).Returns(() => dataSource.GetEnumerator());
var client = new Mock<IDocumentClient>();
client.Setup(_ => _.CreateDocumentQuery<Book>(It.IsAny<Uri>(), It.IsAny<FeedOptions>()))
.Returns(mockDocumentQuery.Object);
var documentsRepository = new DocumentDBRepository<Book>(client.Object, "123", "123");
//Act
var entities = await documentsRepository.GetEntities(predicate);
//Assert
entities.Should()
.NotBeNullOrEmpty()
.And.BeEquivalentTo(expected);
}
This allowed the test to be exercised to completion, behave as expected, and pass the test.
I am running unit tests on code which uses VirtualParthUtility.GetAbsolute, but am having problems mocking the context for this to work.
I've set up a mock context with Moq as follows
private Mock<HttpContextBase> MakeMockHttpContext(string url) // url = "~/"
{
var mockHttpContext = new Mock<HttpContextBase>();
// Mock the request
var mockRequest = new Mock<HttpRequestBase>();
mockRequest.Setup(x => x.ApplicationPath).Returns("/");
mockRequest.Setup(x => x.Path).Returns("/");
mockRequest.Setup(x => x.PathInfo).Returns(string.Empty);
mockRequest.Setup(x => x.AppRelativeCurrentExecutionFilePath).Returns(url);
mockHttpContext.Setup(x => x.Request).Returns(mockRequest.Object);
// Mock the response
var mockResponse = new Mock<HttpResponseBase>();
mockResponse.Setup(x => x.ApplyAppPathModifier(It.IsAny<string>())).Returns((string s) => s);
mockHttpContext.Setup(x => x.Response).Returns(mockResponse.Object);
return mockHttpContext;
}
And attached this to an MVC Controller
_myController.ControllerContext = new ControllerContext(MakeMockHttpContext("~/").Object, new RouteData(), _slideSelectorController);
The code that runs during the test hits the line:
venue.StyleSheetUrl = VirtualPathUtility.ToAbsolute(venue.StyleSheetUrl); // input like "~/styles/screen.css"
Every time this runs, it steps into System.Web.VirtualPathUtility, with the problem that the "VirtualParthString" to be returned always throws an exception:
public static string ToAbsolute(string virtualPath)
{
return VirtualPath.CreateNonRelative(virtualPath).VirtualPathString;
}
The reason for the exception is easy to see in System.Web.VirtualPathString:
public string VirtualPathString
{
get
{
if (this._virtualPath == null)
{
if (HttpRuntime.AppDomainAppVirtualPathObject == null)
{
throw new HttpException(System.Web.SR.GetString("VirtualPath_CantMakeAppAbsolute", new object[] { this._appRelativeVirtualPath }));
}
if (this._appRelativeVirtualPath.Length == 1)
{
this._virtualPath = HttpRuntime.AppDomainAppVirtualPath;
}
else
{
this._virtualPath = HttpRuntime.AppDomainAppVirtualPathString + this._appRelativeVirtualPath.Substring(2);
}
}
return this._virtualPath;
}
}
Through the Watch Window I can see that _virtualPath and HttpRuntime.AppDomainAppVirtualPathString are both null, hence it throws an exception.
If _virtualPath were set, the exception wouldn't happen. But after the VirtualPath.Create method has created a new VirtualPath object, it doesn't set the _virtualPath property before it is returned. An extract from the Create method up to this point is:
VirtualPath path = new VirtualPath();
if (UrlPath.IsAppRelativePath(virtualPath))
{
virtualPath = UrlPath.ReduceVirtualPath(virtualPath);
if (virtualPath[0] == '~')
{
if ((options & VirtualPathOptions.AllowAppRelativePath) == 0)
{
throw new ArgumentException(System.Web.SR.GetString("VirtualPath_AllowAppRelativePath", new object[] { virtualPath }));
}
path._appRelativeVirtualPath = virtualPath;
return path;
So if anyone can suggest how to get this unit test working, that will be very helpful!
Thanks,
Steve
I would just create a wrapper interface. Something like:
public interface IPathUtilities
{
string ToAbsolute(string virtualPath);
}
You can inject that into your controller. At test time, use a stub. At runtime, you'll have a class that implements IPathUtilities and calls VirtualPathUtility.ToAbsolute().
I want to create test case for below method "GetByEmail".
public User GetByEmail(string email, bool includeUserRoles = false, bool includeUserType = false)
{
Expression<Func<User>> whereClause = u => u.Email == email;
return GetQuery(whereClause, includeUserRoles, includeUserType) .FirstOrDefault();
}
private IQueryable<User> GetQuery(Expression<Func<User>> whereClause,
bool includeUserRoles = false, bool includeUserType = false)
{
IQueryable<User> query = base.GetQuery(whereClause);
if (includeUserRoles)
query = query.Include(u => u.UserRoles);
if (includeUserType)
query = query.Include(u => u.UserType);
return query;
}
protected IQueryable<T> GetQuery<T>(Expression<Func<T>> predicate) where T : EntityBase
{
return predicate != null ?
CreateObjectSet<T>().Where(predicate) :
CreateObjectSet<T>();
}
protected IObjectSet<T> CreateObjectSet<T>() where T : EntityBase
{
return _context.CreateObjectSet<T>();
}
public static IQueryable<T> Include<T>(this IQueryable<T> source, Expression<Func<T>> property)
{
var objectQuery = source as ObjectQuery<T>;
if (objectQuery != null)
{
var propertyPath = GetPropertyPath(property);
return objectQuery.Include(propertyPath);
}
return source;
}
Below is my test case method -
[Fact]
private void GetByEmail_PassedEmailAddress_RelatedUser()
{
//Created fake context
var fakeContext = Isolate.Fake.Instance<Entities>();
//Created fake Repository and passed fakeContext to it
var fakeRepository = Isolate.Fake.Instance<Repository>(Members.CallOriginal, ConstructorWillBe.Called, fakeContext);
//Created fake in memory collection of User
var fakeUsers = GetUsers();
Isolate.WhenCalled(() => fakeContext.Context.CreateObjectSet<User>())
.WillReturnCollectionValuesOf(fakeUsers);
var User = Isolate.Invoke.Method(fakeRepository, "GetByEmail", "abc#xyz.com", true, true);
Assert.True(User != null);
}
In the above test case method I successfully get the user with passed email but not able to include other entities of associated user.
Kindly let me know, how can I include other entities with associated User.
Include is leaky abstraction - it works only with EF and linq-to-entities and cannot be successfully used with linq-to-objects. You know that your unit test needs populated relations so your GetUsers method must prepare that data. That is a point of mocking / faking - you don't think about internal implementation of mocked method. You simply return what should be returned.
Btw. what is the point of your test? It looks like you are trying to test a mock - that is wrong. Mock provides correct data and you only need it to test another feature dependent on mocked component.
Tell me if my concept is wrong. I have 2 classes; Country and State. A state will have a CountryId property.
I have a service and a repository as follows:
Service.cs
public LazyList<State> GetStatesInCountry(int countryId)
{
return new LazyList<State>(geographicsRepository.GetStates().Where(s => s.CountryId == countryId));
}
IRepository.cs
public interface IGeographicRepository
{
IQueryable<Country> GetCountries();
Country SaveCountry(Country country);
IQueryable<State> GetStates();
State SaveState(State state);
}
MyTest.cs
private IQueryable<State> getStates()
{
List<State> states = new List<State>();
states.Add(new State(1, 1, "Manchester"));//params are: StateId, CountryId and StateName
states.Add(new State(2, 1, "St. Elizabeth"));
states.Add(new State(2, 2, "St. Lucy"));
return states.AsQueryable();
}
[Test]
public void Can_Get_List_Of_States_In_Country()
{
const int countryId = 1;
//Setup
geographicsRepository.Setup(x => x.GetStates()).Returns(getStates());
//Call
var states = geoService.GetStatesInCountry(countryId);
//Assert
Assert.IsInstanceOf<LazyList<State>>(states);
//How do I write an Assert here to check that the states returned has CountryId = countryId?
geographicsRepository.VerifyAll();
}
I need to verify the information of the states returned. Do I need to write a loop and put the asserts in it?
Assert.IsTrue(states.All(x => 1 == x.CountryId));
I don't know if there is something in nunit for this, but you could do this with linq:
states.All(c => Assert.AreEqual(1, c.CountryId))
EDIT
after quick googling it seems you can do this
Assert.That(states.Select(c => c.CountryId), Is.All.EqualTo(1));
i have just started using Moq ver (3.1) and i have read blogs and what not.... anyway... i guess until you makes your hand dirty you will not learn :)
okay here is what i'm testing...
var newProduct = new Mock<IPartialPerson>();
newProduct.SetupGet(p => p.FirstName).Returns("FirstName");
newProduct.SetupGet(p => p.MiddleName).Returns("MiddleName");
newProduct.SetupGet(p => p.LastName).Returns("LastName");
newProduct.SetupGet(p => p.EmailAddress).Returns("EmailAddress#hotmail.com");
newProduct.SetupGet(p => p.UserID).Returns("UserID");
//mock Escort repository
var mockEscortRepository = new Mock<IEscortRepository>();
mockEscortRepository.Setup(p => p.LoadAllEscorts())
.Returns(newProduct.Object); //error
Error 1 The best overloaded method
match for
'Moq.Language.IReturns>.Returns(System.Collections.Generic.List)'
has some invalid arguments
Error 2 Argument '1': cannot convert
from
'App.Model.Interface.IPartialPerson'
to
'System.Collections.Generic.List'
public interface IPartialPerson
{
string FirstName { get; }
string MiddleName { get; }
string LastName { get; }
string EmailAddress { get; }
string FullName { get; }
string UserID { get; }
}
public interface IEscortRepository
{
List<PartialPerson> LoadAllEscorts();
List<PartialPerson> SelectedEscorts(List<PartialPerson> selectedEscorts);
}
i have two methods that i want to test "LoadAllaEscorts" and "SelectedEscorts"
how would i do a test for both methods?
Try this:
mockEscortRepository
.Setup(p => p.LoadAllEscorts())
.Returns(new List<IPartialPerson>() { newProduct.Object } );
When you say:
.Returns(newProduct.Object)
You are asking Moq to return one specific object. The compiler sees that your method returns a list and so it will not compile unless you provide a list for it to return. So you need to create a list that contains the object you want to return then ask Moq to return that instead.
Based on your comments you might also be interested in testing a list with more than one item. To do that, create a list with more than one item, then ask the Mock to return that. Here is one way you could create a list with more than one item:
List<PartialPerson> escorts = new List<PartialPerson>();
for (int i = 0; i < 10; i++)
{
var escort = new Mock<IPartialPerson>();
escort.SetupGet(p => p.FirstName).Returns("FirstName" + i);
escort.SetupGet(p => p.MiddleName).Returns("MiddleName" + i);
escort.SetupGet(p => p.LastName).Returns("LastName" + i);
escort.SetupGet(p => p.EmailAddress).Returns(i + "EmailAddress#hotmail.com");
escort.SetupGet(p => p.UserID).Returns("UserID" + i);
escorts.Add(escort.Object);
}
mockEscortRepository
.Setup(p => p.LoadAllEscorts())
.Returns(escorts);
Good luck and keep on pimpin!
i have two methods that i want to test
"LoadAllaEscorts" and
"SelectedEscorts"
Those are methods on an interface. You don't write tests against an interface, or against mock objects. You write tests against concrete classes.
Somewhere you have an EscortRepository that implements IEscortRepository. I'm assuming that hits the database. Write integration tests against that.
Elsewhere in your code you probably have a class (call it "Foo") that has an IEscortRepository dependency injected into it (such as via a constructor parameter). When you want to write tests against the Foo class, you would use Moq to create a mock IEscortRepository returning fixed test data and pass that mock object into your Foo instance.
Another issue is that your IEscortRepository methods are returning (or taking as a parameter) List<PartialPerson>. Those should be IList<IPartialPerson> (or IEnumerable<T>, ICollection<T>, or ReadOnlyCollection<T>). The most important part is that the collection items should be an interface type (IPartialPerson).
+1 for magnifico, who had the code right:
using System;
using System.Collections.Generic;
using Moq;
namespace ConsoleApplication1
{
internal class Program
{
private static void Main(string[] args)
{
var newProduct = new Mock<IPartialPerson>();
newProduct.SetupGet(p => p.FirstName).Returns("FirstName");
newProduct.SetupGet(p => p.MiddleName).Returns("MiddleName");
newProduct.SetupGet(p => p.LastName).Returns("LastName");
newProduct.SetupGet(p => p.EmailAddress).Returns("EmailAddress#hotmail.com");
newProduct.SetupGet(p => p.UserID).Returns("UserID");
var mockEscortRepository = new Mock<IEscortRepository>();
mockEscortRepository
.Setup(p => p.LoadAllEscorts())
.Returns(new List<IPartialPerson> {newProduct.Object});
IEscortRepository repository = mockEscortRepository.Object;
IList<IPartialPerson> escorts = repository.LoadAllEscorts();
foreach (IPartialPerson person in escorts)
{
Console.WriteLine(person.FirstName + " " + person.LastName);
}
Console.ReadLine();
// Outputs "FirstName LastName"
}
}
public interface IPartialPerson
{
string FirstName { get; }
string MiddleName { get; }
string LastName { get; }
string EmailAddress { get; }
string FullName { get; }
string UserID { get; }
}
public interface IEscortRepository
{
IList<IPartialPerson> LoadAllEscorts();
IList<IPartialPerson> SelectedEscorts(IList<IPartialPerson> selectedEscorts);
}
}
(The above example is not a unit test; it just shows that Moq works.)
Note that you don't have to use SetupGet for properties; Setup works as well.
Your mock is setup to return a single item, and it should return a List according to the repository interface.