Mocked setup below (the GenerateTrades() and other methods in ContextFactory are just returning a List AsQueryable with sample data):
_trades = ContextFactory.GenerateTrades();
_hedges = ContextFactory.GenerateHedges();
_exposures = ContextFactory.GenerateExposures();
_ctx = new Mock<FxContext>();
var fakeTrades = new Mock<DbSet<Trade>>();
fakeTrades.As<IQueryable<Trade>>().Setup(m => m.Provider).Returns(_trades.Provider);
fakeTrades.As<IQueryable<Trade>>().Setup(m => m.Expression).Returns(_trades.Expression);
fakeTrades.As<IQueryable<Trade>>().Setup(m => m.ElementType).Returns(_trades.ElementType);
fakeTrades.As<IQueryable<Trade>>().Setup(m => m.GetEnumerator()).Returns(_trades.GetEnumerator());
var fakeHedges = new Mock<DbSet<Hedge>>();
fakeHedges.As<IQueryable<Hedge>>().Setup(m => m.Provider).Returns(_hedges.Provider);
fakeHedges.As<IQueryable<Hedge>>().Setup(m => m.Expression).Returns(_hedges.Expression);
fakeHedges.As<IQueryable<Hedge>>().Setup(m => m.ElementType).Returns(_hedges.ElementType);
fakeHedges.As<IQueryable<Hedge>>().Setup(m => m.GetEnumerator()).Returns(_hedges.GetEnumerator());
var fakeExposures = new Mock<DbSet<Exposure>>();
fakeExposures.As<IQueryable<Exposure>>().Setup(m => m.Provider).Returns(_exposures.Provider);
fakeExposures.As<IQueryable<Exposure>>().Setup(m => m.Expression).Returns(_exposures.Expression);
fakeExposures.As<IQueryable<Exposure>>().Setup(m => m.ElementType).Returns(_exposures.ElementType);
fakeExposures.As<IQueryable<Exposure>>().Setup(m => m.GetEnumerator()).Returns(_exposures.GetEnumerator());
_ctx.Setup(c => c.Trades).Returns(fakeTrades.Object);
_ctx.Setup(c => c.Hedges).Returns(fakeHedges.Object);
_ctx.Setup(c => c.Exposures).Returns(fakeExposures.Object);
Part of test code looks like:
_sut = (from x in _ctx.Object.Hedges
where x.Id == ContextFactory.s_hedge01Id
select x).FirstOrDefault();
_ctx.Object.Hedges.Attach(_sut);
_ctx.Object.Entry(_sut).Collection(x => x.HedgedTrades).Load();
On the last line I get an exception:
{"Member 'Load' cannot be called for property 'HedgedTrades' because the entity of type 'Hedge' does not exist in the context. To add an entity to the context call the Add or Attach method of DbSet<Hedge>."}
I have verified that in fact the _sut Hedge is actually an instance of a Hedge (not null or a stub) and as the code seems to indicate, I have attached the Hedge to the context explicitly (though I would think the query should bring the object into the context automagically). Am I missing something?
It seems like here in your test you are mixing two separate approaches. Error you received states that you are trying to access DbContext inherited logic, but it is mocked. If you want to perform your unit tests against database with use of FxContext then do not mock it. If you want test other part of software then you should mock interface that FxContext should implement. This will enable you to fullfil dependency injection principle in your code which will help you then organize your test in more predictable way.
Related
I'm modelling a 3rd party database using Automapper 8 and EF 6.
One of my DTO classes needs to use a Where clause on an association to locate the correct record.
// Community table is mapped and working.
// Mapping breaks when mapping dest.Subjects
cfg.CreateMap<Person, PersonDto>()
// snip many mappings
.ForMember(dest => dest.Id, act => act.MapFrom(src => src.ID))
.ForMember(dest => dest.UserName, act => act.MapFrom(src => src.Community.NetworkLogin))
.ForMember(
dest => dest.Subjects,
act => act.MapFrom(
src => src.Community.StudentClasses.Where(
subject => subject.Year == CurrentSemester.Year && subject.Semester == CurrentSemester.Semester)))
.ForMember(
dest => dest.Contacts,
act => act.MapFrom(
src => src.Community.Contacts.Where(
contact => Contact.UseThis).Select(contact => contact.ContactDetails)));
This code works in production, but I'd really like to Unit Test this model. Running a simple test (get all records in the Mock) I'm hit with a NullReferenceException when it tries to access the Community.StudentClasses object.
I found this answer relating to NullReferenceExceptionexceptions and AutoMapper, which helped me fix the rest of the references in this config, but I'm still having issues with this one. The test works when I remove the Community.StudentClasses mapping.
I'm mocking objects using code similar to:
public static Person Person19788 =>
new SchoolContact
{
ID = 19788,
NetworkLogin = "username",
// Tried various creation methods
// StudentClasses = new List<StudentClass> {new StudentClass()},
// StudentClasses = new List<StudentClass> {new StudentClass {Year = 0, Semester = 0}},
StudentClasses = null,
StudentContacts = null,
Address = Address19788
};
CurrentSemester has been checked, and returns valid non-zero values for Year and Semester.
The strange thing is that the Contacts mapping works fine, even with null values. So I assume that I've broken my Subjects mapping somewhere along the line, but I'm unsure where else to look.
It turns out that the problem was with my Subjects mapping after all.
The top-level associations were mapped correctly, however the lower-level associations were not. (I didn't include these mappings because a) I didn't think about them, and b) there's only so much code that anyone would be willing to wade through).
After fixing up the w > x > y > z mappings everything is working as expected. I thought I'd exhausted all options before posting this question. Lesson learned: don't post to SO until you've slept on it and taken a fresh look at the code the next day.
I'm exporting a method using MEF with the attribute [Export] and I need to consume this method using the Container (obtaining the method using GetExports).
GetExports returns an ExportedDelegate object that I have no idea how to extract the MethodInfo from.
Inspecting with the debugger I see it as a private property and I'm tempted to extract it using reflection but it doesn't feel like the right way of doing this.
Any ideas?
This problem is different than this one. I'm not trying to use [Import], I have to obtain and consume the method from the Container.
Alright guys so that was a tricky one but I'm leaving here as a reference.
All you have to do is to cast the value returned from MEF to a ExportedDelegate and call CreateDelegate the right way:
This sets the Import we want:
var importDefinition = new ImportDefinition(e => true, obj.GetType().FullName, ImportCardinality.ZeroOrMore, false, false);
var objectsWithMethods = container.GetExports(importDefinition)
.Where(x => x.Value is IYourInterface)
.Select(x => x.Value)
.ToList();
This gets the methods of the objects found above (iterate objectsWithMethods in a foreach using objectsWithMethod):
var endPointsImportDefinition = new ImportDefinition(e => true, objectsWithMethod.GetType().FullName, ImportCardinality.ZeroOrMore, false, false);
var endPoints = container.GetExports(endPointsImportDefinition)
.Where(x => x.Value is ExportedDelegate)
.Select(x => x.Value)
.ToList();
And finally to get MethodInfo (which allows you to run the method) you use:
var endPointMethod = (endPoint as ExportedDelegate).CreateDelegate(typeof(Delegate)).GetMethodInfo();
What also could be:
var endPointMethod = (endPoint as ExportedDelegate).CreateDelegate(typeof(Delegate)).Method;
Hope it helps anyone!
I ma writing unit testcases using NUnit and Fake it Easy for MVC4 Controllers.
In one of the controller, I should be getting exception.
ExceptionDetail exception = new ExceptionDetail() { Description = "Test", ErrorCode = ExceptionErrorCode.UserIsDisabled };
Exception ex = new Exception(new Uri("http://localhost//Plat/ManagementSvc/Groups?UserID=" + iD "), exception );
A.CallTo(() => Fake.GetDataAsync<IEnumerable<Group>>(fakeHttpSession, url)).Throws(ex);
My question is instead of passing localhost(new Uri("http://localhost//Plat/ManagementSvc/Groups"), is there a way to fake the url for URI
If the problem is that the exception isn't being thrown when your production code calls GetDataAsync, it could just be that your code is passing in a different Uri. If this is so, you can change which Uri triggers that call by using a different form of argument constraint.
Instead of matching the Uri exactly, you could choose to match any Uri:
A.CallTo(() => Fake.GetDataAsync<IEnumerable<Group>>(fakeHttpSession, A<Uri>.Ignored))
.Throws(ex);
Or you could even be more specific:
A.CallTo(() => Fake.GetDataAsync<IEnumerable<Group>>(fakeHttpSession, A<Uri>.That.Matches(uri => uri.AbsolutePath == "/Plat/ManagementSvc/Groups"))
.Throws(ex);
if that's what's needed. There are many options. Check out the documentation.
Note that there's no faking of a Uri here. You're just telling FakeItEasy what tests to apply to a received Uri in order to decide whether the faked GetDataAsync method should throw
I've got a unit/integration test as follows.
using (var repository = _factory.Get())
{
applicationBefore = repository.Applications
.Include(a => a.AcceptedAgreements)
.Single(a => a.AggregateId == applicationId);
}
// Perform an operation that deletes an Application and all
// related data and then rebuilds it from the event store.
Repo.Application applicationAfter = null;
using (var repository = _factory.Get())
{
applicationAfter = repository.Applications
.Include(a => a.AcceptedAgreements)
.Single(a => a.AggregateId == applicationId);
}
applicationAfter.AcceptedAgreements.ShouldAllBeEquivalentTo(applicationBefore.AcceptedAgreements, options => options
.ExcludingNestedObjects());
The repository reference is a DbContext and AcceptedAgreements is a navigation property.
This test fails with the following message.
Result Message:
FluentAssertions.Execution.AssertionFailedException :
Expected item[0].Application.Id to be 1, but found 2.
<more failures where stuff inside Application is different>
With configuration:
- Use declared types and members
- Compare enums by value
- Include all non-private properties
- Include all non-private fields
- Match member by name (or throw)
- Be strict about the order of items in byte arrays
- FluentAssertions.Equivalency.ShouldAllBeEquivalentToHelper+CollectionMemberOrderingRuleDecorator
If I modify the assertion as follows:
applicationAfter.AcceptedAgreements.ShouldAllBeEquivalentTo(applicationBefore.AcceptedAgreements, options => options
.Excluding(o => o.Application));
Now the test passes.
Please help me understand why ExcludingNestedObjects() doesn't exclude the Application property, which is in fact a nested object, and I have to resort to excluding each navigation property individually. The above code is slightly simplified as I actually have multiple navigation properties and have to exclude each of them individually.
I would like to create a more structured approach to loading the needed entity-tree:
I need a serious amount of data, so I'm doing this using type-safe Includes (just a normal Include but with Lambda's) as shown here.
As I said, I need a lot of data, basically a whole entity tree under 1 parent item.
Now, I could do this doing something like:
context.House
.Include(x => x.Doors)
.Include(x => x.Doors.FirstOrDefault().Joint)
.Include(x => x.Doors.FirstOrDefault().Joint.FirstOrDefault().JointCategory)
.Include(x => x.Doors.FirstOrDefault().Joint.FirstOrDefault().JointCategory.JointType)
.Include(x => x.Windows)
// ... same thing
.Include(x => x.Roof)
// ... same thing
As you can see, this line filled with includes can get quite huge. This is in fact a very simplified sample of the actual code (which doesn't include houses btw)
So what I would like to do is creating methods, responsible for its branch in the tree. Where the method can accept the object query and include the child, and in its turn, call the "child-loader methods". Also, the parent shouldn't matter, as long as it has a property with the type of the child.
This probably does not make much sense so:
public void LoadHouse(int id)
{
// ...
ObjectQuery<House> query = context.House;
// and now?
LoadDoors(query, x => x.Door);
}
public void LoadDoors<T>(ObjectQuery<T> query, ..?..)
{
// ... ?
LoadJoints(...)
}
And so on. But I can't really get my head around it... There's a missing link between the incoming query and calling the child methods.
Has anyone done something like this? Or could anyone give me some pointers?
Try something like this instead:
query = LoadDoors(query, x => x.Door);
Where LoadX returns the result of calling Include.