scott-xu / entityframework.testing Goto Github PK
View Code? Open in Web Editor NEWThis project forked from rowanmiller/entityframework.testing
EntityFramework Testing
License: Apache License 2.0
This project forked from rowanmiller/entityframework.testing
EntityFramework Testing
License: Apache License 2.0
I have some code in a repository pattern class like this
var existing = this.Find(id); //find returns an instance of MyClass or null
if(existing!=null){
this._context.Entry(existing).CurrentValues.SetValues(newvalues);
}
which throws
Member 'CurrentValues' cannot be called for the entity of type 'MyClass' because the entity does not exist in the context. To add an entity to the context call the Add or Attach method of DbSet<MyClass>
I get the impression from examples that this code should work. I think its failing because the mocked DbContext/Dbsets don't work 100% the same as the actually entity framework implementations. Entry correctly pulls out the DbEntity, but it's not actually in the tracked objects?.
Entity framework is currently the bane of my existence when it comes to testing code :(
I have been trying out EntityFramework.Testing.NSubstitute. It was very easy to get up and running and my tests work great in Visual Studio. The tests however, fail when run on the build server. It appears that EntityFramework.Testing.NSubstitute requires NSubstitute 1.8.1.0. The latest version of NSubstitute is now v1.8.2.0. I have reverted to using the older version of NSubstitute for now but was wondering if there were any plans to upgrade EntityFramework.Testing.NSubstitute to work with the latest version of NSubstitute?
Test cases fail if AddOrUpdate extension methods is used. e.g. _context.Patients.AddOrUpdate(patient);
Also if a method is using transactions DbContext.Database.BeginTransaction() then System.Data.Entity.ModelConfiguration.ModelValidationException is thrown.
e.g. using (var transaction = _context.Database.BeginTransaction())
{
//db operations
}
As we know unit testing EF queries actually tests those queries by executing it as Linq to objects that poses some problems with what you must write in your query for test to work and what you do not want to have there because it will unnecessarily complicate the sql query eg:
from x in baseQuery
join y in baseQuery on x.Id equals y.ParentId into z
from q in z.DefaultIfEmpty()
select new { x.Name, ParentName = q.Name };
Is perfectly fine sql query that will result in nulls for ParentName in none is found but tests for it will fail with null pointer exception.
What I would like to propose it and Extension point in your library that would allow ExpressionVisitors to be applied for tests. For the example above it would rewrite it to use
z.DefaultIfEmpty(new TestsSubject())
just fixing the null pointer issue.
Of course this solution is not perfect but it opens community to figuring out ways to mitigate the issue. Check out my fork with working example at https://github.com/rafalFurman/EntityFramework.Testing
Do you have any plans on developing a version of your awesome library for EF7? We used your EntityFrameworkTesting.NSubstitute a lot in our application and in the process of starting the migration from EF6 to EF7, we hit the wall with all our unit tests using your library with EF7.
Thanks.
I just tried using this and the package seems to be missing any binaries.
Reverting to 1.0.7 is a workaround for now.
I got the following error if I upgrade to NSubstitute 4.0 and try to use the sample code to set up a fake dbset.
System.MissingMethodException Method not found: 'System.__Canon NSubstitute.Arg.Any()'. NSubstitute.NSubstituteDbSetExtensions.SetupData[TEntity](DbSet'1 dbSet, ICollection'1 data, Func'2 find)
Note, this is also posted as a question on StackOverflow.
I just started using this library (1.1.5) and created a simple test which is basically a copy from the examples.
var data = new List<ConfigSetting> { };
var cfSet = new Mock<DbSet<ConfigSetting>>()
.Setup(data);
but in the Setup() method I get the build error:
cannot convert from
System.Collections.Generic.List<ConfigSetting> to
System.Linq.Expressions.Expression<System.Action<System.Data.Entity.DbSet<ConfigSetting>>>
Line 41 of MockDbSetExtensions.cs:
mock.As<IQueryable<TEntity>>().Setup(m => m.GetEnumerator()).Returns(query.GetEnumerator());
Will only return one instance of IEnumerator, which when used once will need to be reset (resulting in the appearance of an empty DbSet on any subsequent enumeration). This does not match the regular behaviour of DbSet.GetEnumerator(), and causes problems if either your code or your debugging tries to enumerate all the items in the DbSet a second time.
Related StackOverflow discussion: DbSet mock, no results while calling ToList secondly
I believe (but haven't yet tested) changing the line to a method that returns a new enumerator will also fix the problem here:
mock.As<IQueryable<TEntity>>().Setup(m => m.GetEnumerator()).Returns(() => query.GetEnumerator());
As a follow up to #5 whilst the binaries are now included this particular package fails to be installed and thus the SetupData extension method is missing.
MoqDbSetExtensions.cs is removing from an array while in a foreach causing the action to crash.
Please support EF Core
There is a pull request that someone has implemented that solves this problem for one case. It needs to be done for all implementations, such as MoqDbSetExtensions:
96526ba#diff-7b3254564f11dc162ab9ab6dac35c9dd
Otherwise the only solutions are to replace the Setup's everywhere you call SetupData, or change your system under test to use ToList() so the mock data and the callback mutation are using different containers.
Include is not working when used as an Expression.
Here the example code to reproduce the problem:
`public T Get(Expression<Func<T, bool>> predicate, params Expression<Func<T, object>>[] includes)
{
IQueryable query = _set;
query = query.Where(predicate);
if (includes != null && includes.Length > 0)
foreach (var include in includes)
query = query.Include(include);
return query.FirstOrDefault();
}`
I wanted to use the DbSet.Remove method in some repository tests, but found that the mock DbSet.Remove method was only doing reference comparison. So passing in an object with identical property values (including the primary key) to an existing item in the collection wouldn't cause it to be removed.
My fix was to update the SetupData extension method signature to add an optional "findEntity" parameter:
public static Mock<DbSet<TEntity>> SetupData<TEntity>(
this Mock<DbSet<TEntity>> mock,
ICollection<TEntity> data = null,
Func<object[], TEntity> find = null,
Func<TEntity, TEntity> findEntity = null
) where TEntity : class
And then modify the Remove/RemoveRange callbacks to call it:
mock.Setup(m => m.Remove(It.IsAny<TEntity>())).Callback<TEntity>(entity =>
{
if (findEntity != null) entity = findEntity(entity);
data.Remove(entity);
mock.SetupData(data, find, findEntity);
});
mock.Setup(m => m.RemoveRange(It.IsAny<IEnumerable<TEntity>>())).Callback<IEnumerable<TEntity>>(entities =>
{
foreach (var entity in entities)
{
if (findEntity != null) entity = findEntity(entity);
data.Remove(entity);
}
mock.SetupData(data, find, findEntity);
});
I then setup my mock to compare primary keys instead of object references:
_mockDbSet.SetupData(_testData,
find: ids => _testData.Find(e => e.EntityId == (int)ids[0]),
findEntity: en => _testData.FirstOrDefault(e => en != null && e.EntityId == en.EntityId)
);
Finally, I modified the Add/AddRange callbacks to retain the findEntity parameter:
mock..Setup(m => m.Add(It.IsAny<TEntity>())).Callback<TEntity>(entity =>
{
data.Add(entity);
mock.SetupData(data, find, findEntity);
});
mock.Setup(m => m.AddRange(It.IsAny<IEnumerable<TEntity>>())).Callback<IEnumerable<TEntity>>(entities =>
{
foreach (var entity in entities)
{
data.Add(entity);
};
mock.SetupData(data, find, findEntity);
});
Not sure if there's a better way of doing this, but I think it's a helpful enhancement since DbSet.Remove() is often passed a deserialized object from the service layer rather than an object that was constructed by EF, so the expected behaviour is a primary key comparison, not an object reference comparison.
Could you please add to readme some explanation/links, why we should consider to use Ninject.MockingKernel.NSubstitute instead of just mocking framework.
Could you also remove dots in packages names.
The actual Nuget packages are EntityFrameworkTesting, not EntityFramework.Testing.
I get a warning when building my .NET Core application that includes this NUget package for my unit test project:
"Warning NU1701 Package 'EntityFrameworkTesting.Moq 1.2.1' was restored using '.NETFramework,Version=v4.6.1' instead of the project target framework '.NETCoreApp,Version=v2.0'. This package may not be fully compatible with your project. TaskManager.Tests E:\Documents\Development Projects\Imparta Task Manager Technical Test\TaskManager\TaskManager.Tests\TaskManager.Tests.csproj 1 "
Will you create a version that targets .NET Core 2.0 and upwards?
Currently it is compiled against .Net v4.5 which limits its usability in projects targeted to v4.5.1. Would be great to get this to support v4.5.1.
I went back to a project and while upgrading packages I noticed that the EntityFramework.Testing.FakeItEasy NuGet package does support the latest version of FakeItEasy which is currently v2.2.0?
Are their plans to support versions of FakeItEasy > 2.0.0?
I have set of XUnit tests using EntityFramework.Testing package and when I run them using xunit runner everything is OK:
C:\WhateverProject>.\packages\xunit.runner.console.2.2.0\tools\xunit.console.exe ".\WhateverProject.UnitTests\bin\Release\WhateverProject.UnitTests.dll" -xml TestResults.WhateverProject.xml
xUnit.net Console Runner (64-bit .NET 4.0.30319.42000)
Discovering: WhateverProject.UnitTests
Discovered: WhateverProject.UnitTests
Starting: WhateverProject.UnitTests
Finished: WhateverProject.UnitTests
=== TEST EXECUTION SUMMARY ===
WhateverProject.UnitTests Total: 79, Errors: 0, Failed: 0, Skipped: 0, Time: 8.398s
However when I am using OpenCover.Console.exe to execute the tests and measure the coverage, I am getting DirectoryNotFoundException:
C:\WhateverProject>OpenCover.Console.exe -output:".\opencover.xml" -register:user -mergeoutput -target:".\packages\xunit.runner.cons
ole.2.2.0\tools\xunit.console.exe" -targetargs:"WhateverProject.UnitTests.dll" -targetdir:".\WhateverProject.UnitTests\bin\Release"
Loading coverage file C:\WhateverProject.\opencover.xml
Executing: C:\WhateverProject\packages\xunit.runner.console.2.2.0\tools\xunit.console.exe
xUnit.net Console Runner (64-bit .NET 4.0.30319.42000)
Discovering: WhateverProject.UnitTests
Discovered: WhateverProject.UnitTests
Starting: WhateverProject.UnitTests
Finished: WhateverProject.UnitTests
=== TEST EXECUTION SUMMARY ===
WhateverProject.UnitTests Total: 79, Errors: 0, Failed: 0, Skipped: 0, Time: 10.489s
Committing...
An System.IO.DirectoryNotFoundException occured: Could not find a part of the path 'c:\Users\Scott\Documents\GitHub\scott-xu\EntityFramework.Testing\src\EntityFramework.Testing.Moq\MoqDbSetExtensions.cs'.
An System.IO.DirectoryNotFoundException occured: Could not find a part of the path 'c:\Users\Scott\Documents\GitHub\scott-xu\EntityFramework.Testing\src\EntityFramework.Testing\DebugCheck.cs'.
An System.IO.DirectoryNotFoundException occured: Could not find a part of the path 'c:\Users\Scott\Documents\GitHub\scott-xu\EntityFramework.Testing\src\EntityFramework.Testing\InMemoryAsyncQueryable{T}.cs'.
An System.IO.DirectoryNotFoundException occured: Could not find a part of the path 'c:\Users\Scott\Documents\GitHub\scott-xu\EntityFramework.Testing\src\EntityFramework.Testing\InMemoryAsyncQueryProvider.cs'.
An System.IO.DirectoryNotFoundException occured: Could not find a part of the path 'c:\Users\Scott\Documents\GitHub\scott-xu\EntityFramework.Testing\src\EntityFramework.Testing\InMemoryDbAsyncEnumerator{T}.cs'.
An System.IO.DirectoryNotFoundException occured: Could not find a part of the path 'c:\Users\Scott\Documents\GitHub\scott-xu\EntityFramework.Testing\src\EntityFramework.Testing\TypeExtensions.cs'.
An System.IO.DirectoryNotFoundException occured: Could not find a part of the path 'c:\Users\Scott\Documents\GitHub\scott-xu\EntityFramework.Testing\src\EntityFramework.Testing.Moq\MoqDbSetExtensions.cs'.
An System.IO.DirectoryNotFoundException occured: Could not find a part of the path 'c:\Users\Scott\Documents\GitHub\scott-xu\EntityFramework.Testing\src\EntityFramework.Testing\DebugCheck.cs'.
An System.IO.DirectoryNotFoundException occured: Could not find a part of the path 'c:\Users\Scott\Documents\GitHub\scott-xu\EntityFramework.Testing\src\EntityFramework.Testing\InMemoryAsyncQueryable{T}.cs'.
An System.IO.DirectoryNotFoundException occured: Could not find a part of the path 'c:\Users\Scott\Documents\GitHub\scott-xu\EntityFramework.Testing\src\EntityFramework.Testing\InMemoryAsyncQueryProvider.cs'.
An System.IO.DirectoryNotFoundException occured: Could not find a part of the path 'c:\Users\Scott\Documents\GitHub\scott-xu\EntityFramework.Testing\src\EntityFramework.Testing\InMemoryDbAsyncEnumerator{T}.cs'.
An System.IO.DirectoryNotFoundException occured: Could not find a part of the path 'c:\Users\Scott\Documents\GitHub\scott-xu\EntityFramework.Testing\src\EntityFramework.Testing\TypeExtensions.cs'.
An System.IO.DirectoryNotFoundException occured: Could not find a part of the path 'c:\Users\Scott\Documents\GitHub\scott-xu\EntityFramework.Testing\src\EntityFramework.Testing.Moq\MoqDbSetExtensions.cs'.
An System.IO.DirectoryNotFoundException occured: Could not find a part of the path 'c:\Users\Scott\Documents\GitHub\scott-xu\EntityFramework.Testing\src\EntityFramework.Testing\DebugCheck.cs'.
An System.IO.DirectoryNotFoundException occured: Could not find a part of the path 'c:\Users\Scott\Documents\GitHub\scott-xu\EntityFramework.Testing\src\EntityFramework.Testing\InMemoryAsyncQueryable{T}.cs'.
An System.IO.DirectoryNotFoundException occured: Could not find a part of the path 'c:\Users\Scott\Documents\GitHub\scott-xu\EntityFramework.Testing\src\EntityFramework.Testing\InMemoryAsyncQueryProvider.cs'.
An System.IO.DirectoryNotFoundException occured: Could not find a part of the path 'c:\Users\Scott\Documents\GitHub\scott-xu\EntityFramework.Testing\src\EntityFramework.Testing\InMemoryDbAsyncEnumerator{T}.cs'.
An System.IO.DirectoryNotFoundException occured: Could not find a part of the path 'c:\Users\Scott\Documents\GitHub\scott-xu\EntityFramework.Testing\src\EntityFramework.Testing\TypeExtensions.cs'.
Visited Classes 698 of 1722 (40.53)
Visited Methods 1638 of 5005 (32.73)
Visited Points 4722 of 13432 (35.15)
Visited Branches 2029 of 7089 (28.62)==== Alternative Results (includes all methods including those without corresponding source) ====
Alternative Visited Classes 772 of 2016 (38.29)
Alternative Visited Methods 2545 of 8552 (29.76)
Hi,
Thanks for this great library, we use it a lot in our EF6 projects. We also use NSubstitute and would like to upgrade this to version >=2.0 which is incompatible with the current version of this library. I can see you've committed a patch to fix this dependency (a9a7456), when do you expect to release a new version of the library to NuGet.org?
An update to EF has been released with .net core 3 to allow a .net framework to .net core migration path.
Please, can we have a release that supports EF 6.3 on .net standard?
A quick look at the code base look like there is a need to update the reflection logic in InMemoryAsyncQueryProvider to handle .net core.
Hi guys!
I tried to make a mock for my simple DbContext and It works fine For MockBehavior.Default, But when I try to use MockBehavior.Strict I cannot even get an Object of this mock.
I made some workaround for one exception using additional Setup for Set<> method:
_myContextMock.Setup(x => x.MyEntities).Returns(mockSetObject);
_myContextMock.Setup(x => x.Set<MyEntity>()).Returns(mockSetObject);
but now got:
System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
----> Moq.MockException : IEnumerable.GetEnumerator() invocation failed with mock behavior Strict.
All invocations on the mock must have a corresponding setup.
And it is when I try to get an Object of my Mock, I mean when I use _myContextMock.Object
Hi guys, quick question how hard to add DbQuery support?
My setup:
[TestFixture]
public class SmsServicesTestsMockedProvider
{
private List<Company> _companySet;
[SetUp]
public void Setup()
{
_companySet = new List<Company>
{
new Company
{
Id = 1,
Name = "Salão da Marta",
SmsCredit = 1,
SmsBonus = 1
}
};
var companySetMock = new Mock<DbSet<Company>>().SetupData(_companySet);
var dbMock = new Mock<AmezzeIdentityContext>(MockBehavior.Loose);
dbMock.Setup(ctx => ctx.Companies).Returns(companySetMock.Object);
}
}
My test method calling a service class which uses the context internally:
[Test]
public async Task it_charges_bonus_sms_from_company()
{
var sms = SMS.Types.Sms
.Create(_martaCompanyType, Message.CreateSafeMessage("This will cost 1 SMS bonus"), Destination.Create(_clientType, _mobileType));
var smsStatus = await _smsService.TrySendSmsWithCharges(sms); // <-- The calling point
Assert.NotNull(smsStatus);
Assert.IsTrue(smsStatus.Successful);
Assert.Zero(_companySet.First(x => x.Id == _martaCompanyType.CompanyId).SmsBonus);
Assert.NotZero(_companySet.First(x => x.Id == _martaCompanyType.CompanyId).SmsBonus);
}
The method using the context:
public async Task<ISmsStatus> TrySendSmsWithCharges(Sms sms)
{
//This line is returning null
var company = _context.Companies.Find(sms.Sender.CompanyId);
}
If I use .ToList()
it correctly returns the data from the List<Company>
I've setup.
If I use .FirstOrDefault(x => x.Id == 1)
it also works.
Thus I'm assuming it is really a bug with the .Find()
and .FindAsync()
methods.
Does this work for Entity Framework Core?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.