I was able to do this not by creating and populating a new DbSet(Of TEntity)
, as this Q&A title postulates, but rather by mocking DbSet(Of TEntity)
:
<Extension>
Public Sub Setup(Of TEntity As Class)(Instance As Mock(Of Db.Context), Entities As List(Of TEntity), ContextSetup As Expression(Of Func(Of Db.Context, DbSet(Of TEntity))))
Dim oDbSetReturn As Func(Of DbSet(Of TEntity))
Dim oDbSetSetup As Expression(Of Func(Of Db.Context, DbSet(Of TEntity)))
Dim oDbSetMock As Mock(Of DbSet(Of TEntity))
Dim oDbSet As DbSet(Of TEntity)
oDbSetMock = New Mock(Of DbSet(Of TEntity))
oDbSetMock.Setup(Entities)
oDbSet = oDbSetMock.Object
oDbSetReturn = Function() oDbSet
oDbSetSetup = Function(Context) Context.Set(Of TEntity)
Instance.Setup(ContextSetup).Returns(oDbSet)
Instance.Setup(oDbSetSetup).Returns(oDbSetReturn)
End Sub
This is a companion method to a DbSet(Of TEntity)
setup:
<Extension>
Public Sub Setup(Of TEntity As Class)(Instance As Mock(Of DbSet(Of TEntity)), Entities As List(Of TEntity))
Dim oRemoveRangeReturn As Func(Of IEnumerable(Of TEntity), IEnumerable(Of TEntity))
Dim oRemoveRangeSetup As Expression(Of Func(Of DbSet(Of TEntity), IEnumerable(Of TEntity)))
Dim oAddRangeReturn As Func(Of IEnumerable(Of TEntity), IEnumerable(Of TEntity))
Dim oAddRangeSetup As Expression(Of Func(Of DbSet(Of TEntity), IEnumerable(Of TEntity)))
Dim oRemoveReturn As Func(Of TEntity, TEntity)
Dim oRemoveSetup As Expression(Of Func(Of DbSet(Of TEntity), TEntity))
Dim oAddReturn As Func(Of TEntity, TEntity)
Dim oAddSetup As Expression(Of Func(Of DbSet(Of TEntity), TEntity))
Instance.As(Of IQueryable(Of TEntity)).Setup(Function(Queryable) Queryable.GetEnumerator).Returns(Entities.AsQueryable.GetEnumerator)
Instance.As(Of IQueryable(Of TEntity)).Setup(Function(Queryable) Queryable.ElementType).Returns(Entities.AsQueryable.ElementType)
Instance.As(Of IQueryable(Of TEntity)).Setup(Function(Queryable) Queryable.Expression).Returns(Entities.AsQueryable.Expression)
Instance.As(Of IQueryable(Of TEntity)).Setup(Function(Queryable) Queryable.Provider).Returns(Entities.AsQueryable.Provider)
oRemoveRangeSetup = Function(DbSet) DbSet.RemoveRange(It.IsAny(Of IEnumerable(Of TEntity)))
oAddRangeSetup = Function(DbSet) DbSet.AddRange(It.IsAny(Of IEnumerable(Of TEntity)))
oRemoveSetup = Function(DbSet) DbSet.Remove(It.IsAny(Of TEntity))
oAddSetup = Function(DbSet) DbSet.Add(It.IsAny(Of TEntity))
oRemoveRangeReturn = Function(Range)
Entities = Entities.Except(Range)
Return Entities
End Function
oAddRangeReturn = Function(Range)
Entities.AddRange(Range)
Return Entities
End Function
oRemoveReturn = Function(Entity)
Entities.Remove(Entity)
Return Entity
End Function
oAddReturn = Function(Entity)
Entities.Add(Entity)
Return Entity
End Function
Instance.Setup(oRemoveRangeSetup).Returns(oRemoveRangeReturn)
Instance.Setup(oAddRangeSetup).Returns(oAddRangeReturn)
Instance.Setup(oRemoveSetup).Returns(oRemoveReturn)
Instance.Setup(oAddSetup).Returns(oAddReturn)
End Sub
It's called like this:
Private ReadOnly Property DbContextFactory As Func(Of Db.Context)
Get
Dim oContextMock As Mock(Of Db.Context)
Return Function()
oContextMock = New Mock(Of Db.Context)
oContextMock.Setup(Of Db.City)(Me.Cities, Function(Context) Context.Cities)
oContextMock.Setup(Of Db.Role)(Me.Roles, Function(Context) Context.Roles)
oContextMock.Setup(Of Db.User)(Me.Users, Function(Context) Context.Users)
Return oContextMock.Object
End Function
End Get
End Property
This should work. I'm unable to test it presently, but I'll do so asap and provide the results.
--EDIT 1--
I'm getting an 'Unsupported Expression' error at Instance.Setup(ContextSetup)
. I've opened a ticket at the Moq repo for this.
--EDIT 2--
Once again, stakx
to the rescue.
The solution is found in the casting. Most models want a DbSet(Of T)
, while the two Identity-derived models (Db.Role
and Db.User
) want an IDbSet(Of T)
.
This results in a pair of overloaded extension methods:
<Extension>
Public Sub Setup(Of TEntity As Class)(
Instance As Mock(Of Db.Context),
Entities As List(Of TEntity),
DbSetSetup As Expression(Of Func(Of Db.Context, IDbSet(Of TEntity)))
)
Instance.Setup(DbSetSetup).Returns(DbSet(Entities))
Instance.Setup(MethodSetup(Of TEntity)).Returns(MethodReturn(Entities))
End Sub
<Extension>
Public Sub Setup(Of TEntity As Class)(
Instance As Mock(Of Db.Context),
Entities As List(Of TEntity),
DbSetSetup As Expression(Of Func(Of Db.Context, DbSet(Of TEntity)))
)
Instance.Setup(DbSetSetup).Returns(DbSet(Entities))
Instance.Setup(MethodSetup(Of TEntity)).Returns(MethodReturn(Entities))
End Sub
Private Function MethodSetup(Of TEntity As Class)() As Expression(Of Func(Of Db.Context, DbSet(Of TEntity)))
Return Function(Context) Context.Set(Of TEntity)
End Function
Private Function MethodReturn(Of TEntity As Class)(Entities As List(Of TEntity)) As Func(Of DbSet(Of TEntity))
Return Function() DbSet(Entities)
End Function
Private Function DbSet(Of TEntity As Class)(Entities As List(Of TEntity)) As DbSet(Of TEntity)
With New Mock(Of DbSet(Of TEntity))
.Setup(Entities)
Return .Object
End With
End Function
And finally this all works.
Thanks stakx
.