I am getting a "System.Reflection.TargetParameterCountException: Parameter Count mismatch" exception when attempting to mock our ApiClient.
I am using the following code to Setup the Moq response
private void SetupApiClientForGetZones(IEnumerable<Zone> zone)
{
this.MockHubApiClient.Setup(x => x.GetAsync<IEnumerable<Zone>>(It.IsAny<string>(), It.IsAny<IDictionary<string, string>>()))
.Returns(
(string name) =>
{
return zone == null ? Task.FromResult<IEnumerable<Zone>>(null) : Task.Run(() => zone);
});
this.MockApiClientFactory.Setup(x => x.CreateClient(It.IsAny<string>()))
.Returns(this.MockHubApiClient.Object);
}
The iApiClient interface I attempting to Mock is
public interface IApiClientAsync : IApiClient
{
Task<string> GetAsync(string apiController);
Task<T> GetAsync<T>(string apiController) where T : class;
Task<string> GetAsync(string apiController, IDictionary<string, string> param, string queryString);
Task<T> GetAsync<T>(string apiController, IDictionary<string, string> param) where T : class;
}
My unit test is
[Test]
public void GetZonesNotCached()
{
var data = new List<Zone> { new Zone { ZoneId = 1, ZoneName = "Test Zone 1" }, new Zone { ZoneId = 2, ZoneName = "Test Zone 2" } };
this.SetupApiClientForGetZones(data);
this.MockCache.Setup(x => x.GetItemFromCache<IEnumerable<Zone>>(It.IsAny<string>()));
var organisationService = new OrganisationService(this.MockUnitOfWorkAsync.Object, this.MockApiClientFactory.Object, this.MockCache.Object);
var results = organisationService.GetZones(1, 1).ToList();
Assert.IsNotNull(results);
Assert.AreEqual(3, results.Count, "There should be 3 records returned");
this.MockCache.Verify(x => x.GetItemFromCache<IEnumerable<Zone>>(It.IsAny<string>()), Times.Once());
this.MockHubApiClient.Verify(x => x.GetAsync<IEnumerable<Zone>>(It.IsAny<string>(), It.IsAny<IDictionary<string, string>>()), Times.Once());
}
I have found numerous other posts with the same exception but none of the solutions or examples are the same as mine.
I have been able to successfully Mock the response when calling the GetAsync method that only has the single string paramter.
private void SetupApiClientForAllDealerDetails(IEnumerable<DealerDetail> dealerDetails)
{
this.MockHubApiClient.Setup(
x => x.GetAsync<IEnumerable<DealerDetail>>(It.IsAny<string>()))
.Returns(
(string name) =>
{
return dealerDetails == null ? Task.FromResult<IEnumerable<DealerDetail>>(null) : Task.Run(() => dealerDetails);
});
this.MockApiClientFactory.Setup(x => x.CreateClient(It.IsAny<string>()))
.Returns(this.MockHubApiClient.Object);
}
Any ideas anyone?
If you use an expression in your .Returns instead of a value, then that expression's parameters must match those of the method signature you are mocking.
For example, I found this in SetupApiClientForGetZones:
this.MockHubApiClient.Setup(x => x.GetAsync<IEnumerable<Zone>>(It.IsAny<string>(), It.IsAny<IDictionary<string, string>>()))
.Returns(
(string name) =>
{
return zone == null ? Task.FromResult<IEnumerable<Zone>>(null) : Task.Run(() => zone);
});
When really it should be:
this.MockHubApiClient.Setup(x => x.GetAsync<IEnumerable<Zone>>(It.IsAny<string>(), It.IsAny<IDictionary<string, string>>()))
.Returns<string, IDictionary<string, string>>(
(name, dict) =>
{
return zone == null ? Task.FromResult<IEnumerable<Zone>>(null) : Task.Run(() => zone);
});
Related
I write a test to filter a list.
Service.cs
public async Task<GetAllParticipantsDto> ListAllAsync(GetAllParticipantsRequest queryModel)
{
int count = 0;
var participantsList = participantRepository.AsNoTracking()
.Include(a => a.ParticipantConnections)!.ThenInclude(a => a.Connection)
.Include(a => a.ParticipantApplicationUsers)!.ThenInclude(a => a.ApplicationUser)
.AsQueryable();
if (participantsList != null && !String.IsNullOrEmpty(queryModel.RelatedConnection))
{
participantsList = participantsList.Where(x => x.ParticipantConnections.Any(y => y.Connection.FirstName.ToLower().Contains(queryModel.RelatedConnection.ToLower())) || x.ParticipantConnections.Any(y => y.Connection.LastName.ToLower().Contains(queryModel.RelatedConnection.ToLower())) ||
x.ParticipantConnections.Any(y => (y.Connection.FirstName.ToLower()+ y.Connection.LastName.ToLower()).Contains(queryModel.RelatedConnection.ToLower())) || x.ParticipantConnections.Any(y => (y.Connection.FirstName.ToLower() +" "+ y.Connection.LastName.ToLower()).Contains(queryModel.RelatedConnection.ToLower())));
count = participantsList.Count(); // NullReferenceException Exception thrown in this line
}
}
unit test
public async void ListAllAsync_ShouldReturn_FilterByBy_RelatedConnection()
{
var query = new GetAllParticipantsRequest()
{ // others null
RelatedConnection = "Alice Doe, Bob Doe"
};
Func<DSMP.ApplicationCore.Entities.Participant, bool> exists = n => true; // prepare Func outside of Setup
//1 - create a List<T> with test items
var participantList = ParticipantMockData.ListAllAsyncEntity();
//2 - build mock by extension
var mock = participantList.AsQueryable().BuildMock();
//3 - setup the mock as Queryable for Moq
_participantRepository.Setup(x => x.AsNoTracking(false)).Returns(mock);
var sut = new ParticipantService(
_participantRepository.Object, _participantSupportNeed.Object, _participantConnection.Object, _participantDisability.Object, _participantMedicalCondition.Object, _supportNeed.Object, _disability.Object, _medicalCondition.Object, _participantApplicationUser.Object, _appLogger.Object);
// Act
var result = await sut.ListAllAsync(query);
// Assert
}
The exception
Message - System.NullReferenceException: 'Object reference not set to an instance of an object.'
StackTrace -
" at System.Linq.Enumerable.Any[TSource](IEnumerable1 source, Func2 predicate)\r\n at System.Linq.Enumerable.WhereListIterator1.MoveNext()\r\n at System.Collections.Generic.LargeArrayBuilder1.AddRange(IEnumerable1 items)\r\n at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable1 source)\r\n at System.Linq.Enumerable.ToArray[TSource](IEnumerable1 source)\r\n at System.Linq.SystemCore_EnumerableDebugView1.get_Items()"
I could not find why this error occur.
Can any one help me?
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 have the following controller action method.
[HttpPost]
public ActionResult CreateProvider(Provider provider)
{
try
{
int providerCreationSuccessful = _repository.CreateProvider(provider);
if (providerCreationSuccessful == 2)
TempData["userIntimation"] = "Provider Registered Successfully";
//return RedirectToAction("ShowTheListOfProviders");
}
catch (Exception Ex)
{
_logger.Error(Ex.Message);
return View("Error");
}
return Json(new { url = Url.Action("ShowTheListOfProviders", "Provider") });
}
I had written the following Test case for the above method,which was working
[TestMethod()]
public void CreateProviderTest()
{
mockProviderRepository.Setup(provider => provider.CreateProvider(_provider)).Returns(new int());
var providerCreationResult = _providerController.CreateProvider(_provider) as ActionResult;
Assert.IsNotNull(providerCreationResult);
}
As can be seen from my code in the action method,I am redirecting using AJAX,hence returning JSON of the url to be redirected to.
Now,the test is obviously failing.I am new to unit tests and was wondering,what updates I needed to make to the Testmethod for it to pass.Please guide me.Thanks.
If you want test the Json Result contains the expected URL, you can write a test like below.
[TestMethod]
public void CreateProvider_Execute_EnsureJsonContainsExpectedUrl()
{
var context = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>();
var response = new Mock<HttpResponseBase>();
context.Setup(ctx => ctx.Request).Returns(request.Object);
context.Setup(ctx => ctx.Response).Returns(response.Object);
request.SetupGet(x => x.ApplicationPath).Returns("/");
request.SetupGet(x => x.Url).Returns(new Uri("http://localhost/a", UriKind.Absolute));
response.Setup(x => x.ApplyAppPathModifier(It.IsAny<string>())).Returns<string>(x => x);
context.SetupGet(x => x.Request).Returns(request.Object);
context.SetupGet(x => x.Response).Returns(response.Object);
RouteConfig.RegisterRoutes(new RouteCollection());
var repoStub = new Mock<IRepository>();
repoStub.Setup(x => x.CreateProvider(new Provider())).Returns(1);
var sut = new HomeController(repoStub.Object, new Mock<ILogger>().Object);
sut.Url = new UrlHelper(new RequestContext(context.Object, new RouteData()), routes);
var result = sut.CreateProvider(new Provider()) as JsonResult;
var actualUrl = GetValueFromJsonResult<string>(result, "url");
Assert.AreEqual<string>("/Provider/ShowTheListOfProviders", actualUrl);
}
private T GetValueFromJsonResult<T>(JsonResult jsonResult, string propertyName)
{
var property =
jsonResult.Data.GetType().GetProperties()
.Where(p => string.Compare(p.Name, propertyName) == 0)
.FirstOrDefault();
if (null == property)
throw new ArgumentException("propertyName not found", "propertyName");
return (T)property.GetValue(jsonResult.Data, null);
}
I would like to mock a WebViewPage and compare the output with an expected result.
here are my mockhelpers I'm using
public static class MockHelpers
{
public static HttpContextBase MockHttpContext(NameValueCollection queryStringCollection = null)
{
var request = new Mock<HttpRequestBase>(MockBehavior.Strict);
if(queryStringCollection != null)
SetupMockRequestQuerystringValues(request, queryStringCollection);
request.SetupGet(x => x.ApplicationPath).Returns("/");
request.SetupGet(x => x.Url).Returns(new Uri("http://localhost/a", UriKind.Absolute));
request.SetupGet(x => x.ServerVariables).Returns(new System.Collections.Specialized.NameValueCollection());
var response = new Mock<HttpResponseBase>(MockBehavior.Strict);
response.Setup(x => x.ApplyAppPathModifier(Moq.It.IsAny<String>())).Returns((String url) => url);
// response.SetupGet(x => x.Cookies).Returns(new HttpCookieCollection()); // This also failed to work
var context = new Mock<HttpContextBase>(MockBehavior.Strict);
context.SetupGet(x => x.Request).Returns(request.Object);
context.SetupGet(x => x.Response).Returns(response.Object);
context.SetupGet(x => x.Response.Cookies).Returns(new HttpCookieCollection()); // still can't call the Clear() method
context.SetupGet(p => p.User.Identity.Name).Returns("blah");
context.SetupGet(p => p.User.Identity.IsAuthenticated).Returns(true);
return context.Object;
}
private static void SetupMockRequestQuerystringValues( Mock<HttpRequestBase> request, NameValueCollection queryStringCollection)
{
request.SetupGet(x => x.QueryString).Returns(queryStringCollection);
}
public static ViewContext MockViewContext()
{
return CreateSimpleGenericMock<ViewContext>();
}
public static T MockWebViewPage<T>() where T : WebViewPage
{
var mock = new Mock<T>(MockBehavior.Loose) { CallBase = true };
mock.SetupGet(x => x.Context).Returns(MockHttpContext());
mock.SetupGet(x => x.Layout).Returns("layoutName");
mock.SetupGet(x => x.VirtualPath).Returns("virtualPathName");
mock.SetupGet(x => x.Page).Returns(new object{});
mock.SetupGet(x => x.PageData).Returns(new Dictionary<object, dynamic>()
{
{new object(), new object()}
});
var page = mock.Object;
//var helper = new HtmlHelper<object>(new ViewContext { ViewData = CreateSimpleGenericMock<ViewDataDictionary>() }, page, CreateSimpleGenericMock<RouteCollection>());
var helper = new HtmlHelper<object>(new ViewContext { ViewData = new ViewDataDictionary() }, page, new RouteCollection());
page.ViewContext = MockViewContext();
page.Html = helper;
return page;
}
public static T CreateSimpleGenericMock<T>() where T : class
{
var mock = new Mock<T>();
return mock.Object;
}
}
In the MockWebViewPage method you can see all that I have faked. My test method looks like so
[TestMethod]
public void TestMethod1()
{
var coreMasterTestClass = MockHelpers.MockWebViewPage<CoreMaster<object>>();
coreMasterTestClass.ExecutePageHierarchy();
var output = coreMasterTestClass.Html;
}
Is it possible to test the output that will be generated with mocking, and if not does anyone have any possible clues how I could test this. Please note that I'm not testing actual chstml pages but core pages within our own framework.
I got this really cool Moq method that fakes out my GetService, looks like this
private Mock<IGetService<TEntity>> FakeGetServiceFactory<TEntity>(List<TEntity> fakeList) where TEntity : class, IPrimaryKey, new()
{
var mockGet = new Mock<IGetService<TEntity>>();
mockGet.Setup(mock => mock.GetAll()).Returns(fakeList);
mockGet.Setup(mock => mock.Get(It.IsAny<int>())).Returns((int i) => fakeList.Find(fake => fake.Id.ToString() == i.ToString()));
mockGet.Setup(mock => mock.Get(It.IsAny<Expression<Func<TEntity, bool>>>())).Returns((Expression<Func<TEntity, bool>> expression) => fakeList.AsQueryable().Where(expression));
return mockGet;
}
and to use this...
var fakeList = new List<Something>();
fakeList.Add(new Something { Whatever = "blah" });
//do this a buncha times
_mockGetService = FakeGetServiceFactory(fakeList);
_fakeGetServiceToInject = _mockGetService.Object;
How do I toss this into Rhino.Mock?
Something along these lines (sorry, I don't have VS handy, so I can't test it):
private IGetService<TEntity> FakeGetServiceFactory<TEntity>(List<TEntity> fakeList) where TEntity : class, IPrimaryKey, new()
{
var mockGet = MockRepository.GenerateMock<IGetService<TEntity>>();
mockGet.Expect(mock => mock.GetAll()).Return(fakeList);
mockGet.Expect(mock => mock.Get(Arg<int>.Is.Anything)).Do((int i) => fakeList.Find(fake => fake.Id.ToString() == i.ToString()));
mockGet.Expect(mock => mock.Get(Arg<Expression<Func<TEntity, bool>>>.Is.Anything)).Do((Expression<Func<TEntity, bool>> expression) => fakeList.AsQueryable().Where(expression));
return mockGet;
}