NUnit test not working with Entity Framework ToListAsync() - entity-framework-6.1

The source IQueryable doesn't implement IDbAsyncEnumerable.
Only sources that implement IDbAsyncEnumerable can be used for Entity Framework asynchronous operations.
For more details see http://go.microsoft.com/fwlink/?LinkId=287068.
I am new to NUnit.
I have developed the Nunit test cases for` async queries.
But I am getting above error. I refereed https://msdn.microsoft.com/en-us/data/dn314429.aspx link but not able
to solve error.
Any kind of help will be appreciated!
Thanks in advance!
public interface IWork : IDisposable
{
IBlogRepository BlogRepository { get; }
IDBContext Db { get; }
}
public class BlogRepository : GenericRepository<Blog>, IBlogRepository
{
internal ContainerRepository(IWork work)
: base(work)
{
}
}
public interface IBlogRepository : IGenericRepository<Blog>
{
}
[TestFixture]
public class AsyncQueryTests
{
[Test]
public async Task GetAllBlogsAsync_orders_by_name()
{
using (var work = ObjectFactory.GetInstance<IWork>())
{
var data = new List<Blog>
{
new Blog { Name = "BBB" },
new Blog { Name = "ZZZ" },
new Blog { Name = "AAA" },
}.AsQueryable();
var mockSet = new Mock<DbSet<Blog>>();
mockSet.As<IDbAsyncEnumerable<Blog>>()
.Setup(m => m.GetAsyncEnumerator())
.Returns(new TestDbAsyncEnumerator<Blog>(data.GetEnumerator()));
mockSet.As<IQueryable<Blog>>()
.Setup(m => m.Provider)
.Returns(new TestDbAsyncQueryProvider<Blog>(data.Provider));
mockSet.As<IQueryable<Blog>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<Blog>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<Blog>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
var mockContext = new Mock<IWork>();
mockContext.Setup(c => c.BlogRepository.GetQuery()).Returns(mockSet.Object);
ObjectFactory.Configure(cfg => cfg.For<IWork>().Use(mockContext.Object));
foreach (var blog in mockSet.Object)
{
mockContext.Object.BlogRepository.Add(blog);
}
var service = new BlogController();
var blogs = await service.GetAllBlogsAsync();
Assert.AreEqual(3, blogs.Count);
}
}
}

Related

bUnit Unit Test not working as expected with Async

I have the following Unit Test:
[Fact]
public void FetchStudents_Rendered_Test()
{
var testData = new List<Student>()
{
new Student()
{
Id = 1,
Name = "Sample Name",
Email = "sample#email.com",
Phone = "123456789",
Address = "Sample address"
}
};
var mockDbSet = Mock.Of<DbSet<Student>>(dbSet => dbSet.AsQueryable() == testData.AsQueryable());
DbContextOptions<ApplicationDbContext> options = new DbContextOptionsBuilder<ApplicationDbContext>()
.UseInMemoryDatabase(databaseName: "StudentsTest")
.Options;
var mockDbContext = new Mock<ApplicationDbContext>(options);
using var ctx = new TestContext();
ctx.Services.AddSingleton<IStudentsService>(new StudentsService(mockDbContext.Object));
// RenderComponent will inject the service in the WeatherForecasts component
// when it is instantiated and rendered.
var cut = ctx.RenderComponent<FetchStudents>();
// Assert that service is injected
Assert.NotNull(cut.Instance.students);
}
The StudentService looks like below:
public class StudentsService : IStudentsService
{
private readonly ApplicationDbContext _db;
public StudentsService(ApplicationDbContext db)
{
_db = db;
}
public async Task<List<Student>> GetStudentsAsync()
{
return await _db.Students.ToListAsync();
}
}
When I run the unit test I get the following error:
System.InvalidOperationException: 'The source 'IQueryable' doesn't implement 'IAsyncEnumerable<BlazorStudentApp.Data.Models.Student>'. Only sources that implement 'IAsyncEnumerable' can be used for Entity Framework asynchronous operations.'
I have tried setting up the DbSet in multiple different ways, but I keep getting the same error.
What am I missing here?

How to Automoq concrete class dependencies through Automoq?

In my class constrctur, we had multiple concrete class dependencies. as per automoq documentation, we can only interface or abstraction.
System Under Test Class, in that ManageLocationRepository is concrete class dependency.
public class CityEventListener : IEvent<LocationChangeEventData>
{
private readonly ILocationAdapterCaller _locationAdapterCaller;
private readonly ManageLocationRepository _managerLocationRepository;
public CityEventListener(ILocationAdapterCaller locationAdapterCaller, ManageLocationRepository managerLocationRepository)
{
_locationAdapterCaller = locationAdapterCaller;
_managerLocationRepository = managerLocationRepository;
}
public async Task<bool> ProcessEvent(LocationChangeEventData eventData)
{
}
}
Test Case -
[Theory(DisplayName = "Valid value test")]
[ClassAutoMoqData(typeof(ValidValueTests))]
public async Task ProcessEvent_WithCreateOrUpdateOperation_CallsUpsertCityAndReturnsResult(ExpectedValueTestData<Parameters, bool> data,
[Frozen] Mock<ILocationAdapterCaller> locationAdapterCallerMock, [Frozen] Mock<ManageLocationRepository> managerLocationRepositoryMock,
CityEventListener sut)
{
// fakes
var cityDetail = _fixture.Build<CityDetail>()
.With(x => x.Id, data.Params.locationChangeEventData.Id).Create();
// Arrange
locationAdapterCallerMock.Setup(mock => mock.GetCityDetail(data.Params.locationChangeEventData.Id))
.ReturnsAsync(cityDetail).Verifiable();
managerLocationRepositoryMock
.Setup(mock => mock.UpsertCity(cityDetail))
.ReturnsAsync(data.ExpectedValue).Verifiable();
var result = await sut.ProcessEvent(data.Params.locationChangeEventData);
// Assert
using (new AssertionScope())
{
Assert.IsType<bool>(result);
Assert.Equal(data.ExpectedValue, result);
locationAdapterCallerMock.Verify();
managerLocationRepositoryMock.Verify();
}
}
ClassAutoMoq Attribute
public class ClassAutoMoqDataAttribute : CompositeDataAttribute
{
public ClassAutoMoqDataAttribute(Type values)
: base(new ClassDataAttribute(values), new AutoMoqDataAttribute())
{
}
}
public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute() : base(() =>
{
var fixture = new Fixture().Customize(new CompositeCustomization(
new AutoMoqCustomization() { ConfigureMembers = true, GenerateDelegates = true },
new SupportMutableValueTypesCustomization()));
fixture.Behaviors.OfType<ThrowingRecursionBehavior>().ToList().ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new OmitOnRecursionBehavior());
return fixture;
})
{
}
}
what are the alternate way to moq such dependencies through automoq attribute.
I solved my problem by taking two actions -
mark concrete class method virtual
create custom class automoq attribute to freeze dependencies
public class CityEventListenerClassAutoMoqAttribute : CompositeDataAttribute
{
public CityEventListenerClassAutoMoqAttribute(Type values)
: base(new ClassDataAttribute(values), new CityEventListenerAutoMoqAttribute())
{
}
}
public class CityEventListenerAutoMoqAttribute : AutoDataAttribute
{
public CityEventListenerAutoMoqAttribute()
: base(() =>
{
var fixture = new Fixture().Customize(new CompositeCustomization(
new AutoMoqCustomization() { ConfigureMembers = true, GenerateDelegates = true },
new SupportMutableValueTypesCustomization()));
var managerLocationRepositoryMock =
fixture.Freeze<Mock<ManageLocationRepository>>();
fixture.Inject(managerLocationRepositoryMock.Object);
return fixture;
})
{
}
}
Now my test case looks like this -
[Theory(DisplayName = "Valid value test")]
[CityEventListenerClassAutoMoq(typeof(ValidValueTests))]
public async Task ProcessEvent_WithCreateOrUpdateOperation_CallsUpsertCityAndReturnsResult(ExpectedValueTestData<Parameters, bool> data,
[Frozen] Mock<ILocationAdapterCaller> locationAdapterCallerMock, [Frozen] Mock<ManageLocationRepository> managerLocationRepositoryMock,
CityEventListener sut)
{
// fakes
var cityDetail = _fixture.Build<CityDetail>()
.With(x => x.Id, data.Params.locationChangeEventData.Id).Create();
// Arrange
locationAdapterCallerMock.Setup(mock => mock.GetCityDetail(data.Params.locationChangeEventData.Id))
.ReturnsAsync(cityDetail).Verifiable();
managerLocationRepositoryMock
.Setup(mock => mock.UpsertCity(cityDetail))
.ReturnsAsync(data.ExpectedValue).Verifiable();
var result = await sut.ProcessEvent(data.Params.locationChangeEventData);
// Assert
using (new AssertionScope())
{
Assert.IsType<bool>(result);
Assert.Equal(data.ExpectedValue, result);
locationAdapterCallerMock.Verify();
managerLocationRepositoryMock.Verify();
}
}
Do let me know if I can improve anything in my approach.

XUnit mocked db connection dapper error, 'Object is not set to an instance of an object' when executing sql statement

I am trying to unit test my service layer as advised by #NKosi Here. I am able to do the integration test successfully by implementing the actual factory implementation without mocking anything but can't do the unit test (by mocking IDbConnection and my SQL connection factory class) as Dapper query executing fails with the error 'Object not set to an instance of an object'.
My IDbConnection factory and its implementation is as follow
public interface IDbConnectionFactory
{
IDbConnection CreateConnection();
}
public class ConnectionSetings
{
public string Name { get; set; }
}
public class SqlConnectionFactory : IDbConnectionFactory
{
private readonly ConnectionSetings connectionSettings;
public SqlConnectionFactory(ConnectionSetings connectionSettings)
{
this.connectionSettings = connectionSettings;
}
public IDbConnection CreateConnection()
{
return new SqlConnection(connectionSettings.Name);
}
}
And the XUnit test is as follow
[Fact]
public void Get_RestaurantById_ReturnsRestaurant()
{
//Arrange
var connection = new Mock<IDbConnection>();
var dbConnectionFactory = new Mock<IDbConnectionFactory>();
dbConnectionFactory.Setup(x => x.CreateConnection()).Returns(connection.Object);
//Act
var result = new SqlRestaurantDataCL(dbConnectionFactory.Object).Get(1);
//Assert
result.Name.Equals("Test Name 1");
//Assert.Equal("Test Name 1", result.Name);
}
And the Service Layer is as follow
public class SqlRestaurantDataCL : IRestaurantDataCL
{
private readonly IDbConnectionFactory factory;
public SqlRestaurantDataCL(IDbConnectionFactory factory)
{
this.factory = factory;
}
public Restaurant Get(int id)
{
using (var connection = factory.CreateConnection())
{
var selectSql = #"SELECT * From Restaurants Where Id = #Id";
var restaurant = connection.QuerySingleOrDefault<Restaurant>(selectSql, new
{
id
});
return restaurant;
}
}
}
Following is the error screenshot
Following is the answer to my question if anyone is in similar situation. Before following this solution, I would suggest to read #NKosi comments above and consult #Mikhail's solution Here.
ServiceStack.OrmLite.Sqlite package added to use in memory appraoch
internal class InMemoryDatabase
{
private readonly OrmLiteConnectionFactory dbFactory = new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider);
public IDbConnection OpenConnection() => this.dbFactory.OpenDbConnection();
public void Insert<T>(IEnumerable<T> items)
{
using (var db = this.OpenConnection())
{
db.CreateTableIfNotExists<T>();
foreach (var item in items)
{
db.Insert(item);
}
}
}
}
Data Access layer is as follow
public IEnumerable<Restaurant> GetAll()
{
using (var connection = factory.CreateConnection())
{
//return connection.Query<Restaurant>("Select * From [dbo].[Restaurants] Order By Name");
return connection.Query<Restaurant>("Select * From Restaurant Order By Name");
}
}
Unit test is as follow
[Fact]
public void Get_RestaurantById_ReturnsRestaurant()
{
//Arrange
var restaurants = new List<Restaurant>
{
new Restaurant { Id = 1, Name = "Test Name 1", Cuisine = CuisineType.None},
new Restaurant { Id = 2, Name = "Test Name 2", Cuisine = CuisineType.French},
new Restaurant { Id = 3, Name = "Test Name 3", Cuisine = CuisineType.German},
new Restaurant { Id = 4, Name = "Test Name 4", Cuisine = CuisineType.Italian},
new Restaurant { Id = 5, Name = "Test Name 5", Cuisine = CuisineType.None}
};
var db = new InMemoryDatabase();
db.Insert(restaurants);
var connection = new Mock<IDbConnection>();
var dbConnectionFactoryMock = new Mock<IDbConnectionFactory>();
dbConnectionFactoryMock.Setup(c => c.CreateConnection()).Returns(db.OpenConnection());
//Act
var result = new SqlRestaurantDataCL(dbConnectionFactoryMock.Object).GetAll();
//Assert
result.Should().BeEquivalentTo(restaurants);
}

How do I mock the DB models?

I am trying to test a repository and so need to mock the Model Container. Really all I need is to be able to set the Blogs returned to GetBlogs() in the BlogRepository. The repository code is:
private BlogWebsiteModelContainer context;
public BlogRepository(BlogWebsiteModelContainer context)
{
this.context = context;
}
public IEnumerable<Blog> GetBlogs()
{
return context.Blogs;
}
So I want to be able to set what context.Blogs is. I am using Moq and have tried the following:
var mockBlogSet = new Mock<DbSet<Blog>>();
context.Setup(m => m.Blogs).Returns(mockBlogSet.Object);
blogRepo = new BlogRepository(context.Object);
But I get this error message when I debug:
Invalid setup on a non-virtual (overridable in VB) member: m => m.Blogs
Any help greatly appreciated.
Create an interface for your BlogWebsiteModelContainer, then mock the interface. Also instead of defining Blogs on the interface as DbSet<Blog> define it as IQuerayable<Blog>
You can then create a List and use the .AsQueryable extension:
var contextMock = new Mock<IBlogWebsetModelContainer>();
var mockBlogSet = new List<Blog>();
contextMock.Setup(m => m.Blogs).Returns(mockBlogSet.AsQueryable());
blogRepo = new BlogRepository(contextMock.Object);
I found the answer at this link http://msdn.microsoft.com/en-us/data/dn314429.aspx. And so my code became the following:
List<Blog> blogs = new List<Blog>
{
new Blog() { Id = 1 },
new Blog() { Id = 2 },
new Blog() { Id = 3 },
};
var data = blogs.AsQueryable();
var mockSet = new Mock<DbSet<Blog>>();
mockSet.As<IQueryable<Blog>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<Blog>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<Blog>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<Blog>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
var mockContext = new Mock<BlogWebsiteModelContainer>();
mockContext.Setup(c => c.Blogs).Returns(mockSet.Object);
blogRepo = new BlogRepository(mockContext.Object);
Then I had to go into my BlogWebsiteModelContainer class and change:
public DbSet<Blog> Blogs { get; set; }
to
public virtual DbSet<Blog> Blogs { get; set; }
Just adding the virtual in. And it all worked.
Quick note: reason for creating the list first and then making it .AsQueryable() was so in my code I had the original blog list separate so I could compare it in my tests.

Mock MVC WebViewPage using Moq

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.