I am trying to mock HttpRequestBase and HttpSessionStateBase objects and test my code with Moq mocking framework.
This is the relevant part of my setup.
_httpSessionStateBase = _mockRepository.Create<HttpSessionStateBase>();
_motorWebSession = new MotorWebSession
{
PersonaIdentifier = Guid.NewGuid(),
NameIdentifier = Guid.NewGuid(),
MiCurrentPageId = Guid.NewGuid(),
MiSessionId = Guid.NewGuid(),
};
_httpSessionStateBase.SetupGet(e => e.Count).Returns(1);
var keysCollection = new NameValueCollection { { "MotorSession", "MotorSession" } };
_httpSessionStateBase.SetupGet(e => e.Keys).Returns(keysCollection.Keys);
_httpSessionStateBase.Object[0] = _motorWebSession;
_httpSessionStateBase.Object["MotorSession"] = _motorWebSession;
_httpContextBase = _mockRepository.Create<HttpContextBase>();
_httpContextBase.SetupGet(h => h.Session).Returns(_httpSessionStateBase.Object);
In the current implementation this code is called within a test.
var webSession = _httpContext.Current.Session;
var sessionObject = webSession.Keys.Cast<string>()
.Where(w => webSession[w] is WebSessionBase)
.Select(s => webSession[s])
.ToList().FirstOrDefault();
During the Where clause sessionObject results into null which prevents any other subsequent code to run correctly. Is there something wrong I am doing with the setup? Or could the code be altered to work for this setup? It worked with Rhino.Mocks but I am trying to change it to Moq.
Instead of _httpSessionStateBase.Object["MotorSession"] = _motorWebSession; call _httpSessionStateBase.Setup( s => s["MotorSession"]).Returns(_motorWebSession);. Moq mocked objects can't be assigned directly even through index using the [] operator. The correct way to do that is to make a setup.
Related
I need to mock my IVehicleRecordsRepository for some tests. So here's the repo interface:
public interface IVehicleRecordsRepository
{
Task<VehicleRecord> StoreAsync(VehicleRecord veh, Guid? userId = null);
//...
}
and now I try to mock it in the xUnit test so StoreMethod() should return the same value that was passed in as a parameter. Here's the test that tests this scenario:
[Fact]
public async Task ShouldGetValueFromMockedMethod()
{
var mockRepo = new Mock<IVehicleRecordsRepository>();
mockRepo
.Setup(repo => repo.StoreAsync(It.IsAny<VehicleRecord>(), Guid.NewGuid()))
.ReturnsAsync((VehicleRecord veh, Guid userId) => veh)
// tried this too -> .Returns((VehicleRecord veh, Guid userId) => Task.FromResult(veh))
;
VehicleRecord vr = new VehicleRecord(newVehicle, Guid.NewGuid());
var testVeh = await mockRepo.Object.StoreAsync(vr);
Assert.NotNull(testVeh); // ====> FAILS HERE
Assert.AreEqual(vr, testVeh);
}
So, how can I get the same value I passed into StoreAsync() in return ?
Moq version: 4.7.99.0
I've not used Moq, so forgive my ignorance.
In your act statement:
var testVeh = await mockRepo.Object.StoreAsync(vr);
you're only passing in the Vehicle Record ('vr'), but your mocked object is set up to also expect a Guid.NewGuid(), correct?
mockRepo.Setup(repo => repo.StoreAsync(It.IsAny<VehicleRecord>(), Guid.NewGuid()))
Could it be that it's not matching the expectation and therefore, never calls the "(mockObject.)ReturnsAsync" method?
Have you tried doing something like:
var guid = Guid.NewGuid;
VehicleRecord vr = new VehicleRecord(newVehicle, guid);
var testVeh = await mockRepo.Object.StoreAsync(vr, guid);
Or, perhaps simplifying it a bit, change your mockObject to not expect a Guid, since you're passing in only the VehicleRecord:
mockRepo.Setup(repo => repo.StoreAsync(It.IsAny<VehicleRecord>()))
I wrote the unit test using MOQ. When setup the mock I am trying to create the object of class in Linq query. After that I am trying to run the Unit test, but I get below error message.
"When called from 'VisitMemberInit', rewriting a node of type
'System.Linq.Expressions.NewExpression' must return a non-null value
of the same type. Alternatively, override 'VisitMemberInit' and change
it to not visit children of this type."
I have written code like below -
_mockLdapAuthenticatorService.Setup(x => x.Authenticate(
new LoginRequest {
Username = It.IsAny<string>(),
Password = It.IsAny<string>() })).
Returns(new AuthenticationResult { Success = true });
Update the setup. The following is probably what you were trying to achieve.
_mockLdapAuthenticatorService
.Setup(x => x.Authenticate(It.IsAny<LoginRequest>()))
.Returns(new AuthenticationResult { Success = true });
For me, a problem was this new operator when sending parameters to a function. When I create a variable for it and then send the variable as a parameter it worked without error.
NO:
var absentUser = _fixture.Create<User>();
var absentUsers = new List<User> { absentUser }.AsQueryable();
_unitOfWorkMock.Setup(_ => _.UserRepository
.GetAllConfirmedUsersForGroupIds(new List<int> { It.IsAny<int>() }))
.Returns(absentUsers);
YES:
var absentUser = _fixture.Create<User>();
var absentUsers = new List<User> { absentUser }.AsQueryable();
var groupIds = new List<int> { It.IsAny<int>() };
_unitOfWorkMock.Setup(_ => _.UserRepository.GetAllConfirmedUsersForGroupIds(groupIds))
.Returns(absentUsers);
I'm attempting to mock and setup chained methods using Moq.
Here is the method I am trying to mock:
TeamMember teamMember = _unitOfWork
.TeamMembers
.Query()
.ToList()
.Where(t => t.AssociationCode.ToString() == code
&& Crypto.EncryptStringAES(t.Id.ToString(), sharedSecret) == hash)
.SingleOrDefault();
and here is where I attempt to mock it:
var unitOfWorkMock = new Mock<IUnitOfWork>();
var iQueryableMock = new Mock<IQueryable<TeamMember>>();
var iToListMock = new Mock<List<TeamMember>>();
var whereMock = new Mock<IList<TeamMember>>();
var singleMock = new Mock<IEnumerable<TeamMember>>();
unitOfWorkMock
.Setup(u => u.TeamMembers
.Query())
.Returns(iQueryableMock.Object);
iQueryableMock
.Setup(i => i.ToList())
.Returns(iToListMock.Object); //This line throws the error
whereMock
.Setup(w =>
w.Where(It.IsAny<Func<TeamMember, bool>>()))
.Returns(singleMock.Object);
singleMock
.Setup(s =>
s.SingleOrDefault())
.Returns(new TeamMember()
{
Email = "Test#TeamMember.com"
});
When I run this test it gives me this error:
Expression references a method that does not belong to the mocked object: i => i.ToList<TeamMember>()
I have looked at this question already and have tried to do something similar, but I must be missing something.
I am new to this, so if anyone can help me out it will be greatly appreciated.
Your method chain mocking looks fine, but your problem is that ToList is an extension method, which Moq cannot mock.
I want to test that a method adds a record to a DBSet under a certain condition:
public static void AddTriggeredInternalTransactions(IDataContext dc, ExternalTransaction transaction)
{
if (transaction [meets condition A])
dc.InternalTransactions.CreateInverseTransaction(transaction);
// do other stuff under other conditions
}
private static void CreateInverseTransaction(this IDbSet<InternalTransaction> transactions, ExternalTransaction from)
{
var internalTransaction = transactions.Create();
from.CopyToInternalTransaction(internalTransaction);
transactions.Add(internalTransaction);
}
Now, I already have tests for CopyToInternalTransaction(). I just need to call AddTriggeredInternalTransactions() and verify that [condition A] results in the new record being added).
I started with http://msdn.microsoft.com/en-us/data/dn314429.aspx, then used other Google and StackOverflow searches. Before tackling my "real" test, I'm trying to do a simple test just to verify whether a record has been added to a dataset, but I'm stuck on this. Can anyone point out my flaw(s)?
var internals = new Mock<DbSet<InternalTransaction>>();
var theData = new List<InternalTransaction>().AsQueryable();
internals.As<IQueryable<InternalTransaction>>().Setup(m => m.Provider).Returns(theData.Provider);
internals.As<IQueryable<InternalTransaction>>().Setup(m => m.Expression).Returns(theData.Expression);
internals.As<IQueryable<InternalTransaction>>().Setup(m => m.ElementType).Returns(theData.ElementType);
internals.As<IQueryable<InternalTransaction>>().Setup(m => m.GetEnumerator()).Returns(theData.GetEnumerator());
var mockDC = new Mock<IDataContext>();
mockDC.Setup(q => q.InternalTransactions).Returns(internals.Object);
mockDC.Setup(q => q.InternalTransactions.Create()).Returns(new InternalTransaction());
mockDC.Setup(q => q.InternalTransactions.Add(It.IsAny<InternalTransaction>()));
var it = mockDC.Object.InternalTransactions.Create();
it.Id = "123";
mockDC.Object.InternalTransactions.Add(it);
internals.Verify(e => e.Add(It.Is<InternalTransaction>(d => d.Id == "123")), Times.Once());
//or: Assert.Equal(1, mockDC.Object.InternalTransactions.Count());
This test fails with: Expected invocation on the mock once, but was 0 times: e => e.Add(It.Is(d => d.Id == "123")) No setups configured. No invocations performed.
The Assert statement, if used instead, fails with a NotImplementedException: "The member IQueryable.Provider has not been implemented on type DbSet~1Proxy_1 which inherits from DbSet1. Test doubles for DbSet1 must provide implementations of methods and properties that are used."
After comments by Adam and Stuart plus further experimentation, I was able to reduce my test case to the following working test case:
var internals = new Mock<DbSet<InternalTransaction>>();
var mockDC = new Mock<IDataContext>();
mockDC.Setup(q => q.InternalTransactions).Returns(internals.Object);
internals.Setup(q => q.Create()).Returns(new InternalTransaction());
var transaction = new ExternalTransaction { [set criteria for Condition A] };
SomeBusinessObject.AddTriggeredInternalTransactions(mockDC.Object, transaction);
// verify the Add method was executed exactly once
internals.Verify(e => e.Add(It.IsAny<InternalTransaction>()), Times.Once());
*Update Edit - Partial Solution - Help still needed * - I found that the exception was just misleading. It was giving me this exception as I had got the number of times the mocked property was called wrong. It should have been called twice, instead of once. That part works now.
But I still do not understand why the entity is not being removed from the list. Is it because it is queryable?
Original Question Below
I have been trying to follow this link to learn how to unit Entity
Framework 6 and 6.1.
However it does not show how to unit test a delete operation. Here is the
code I am trying to test:
public void DeleteRequirement(int id)
{
Requirement requirementToDelete = GetRequirement(id);
context.Requirement.Remove(requirementToDelete);
context.SaveChanges();
}
public Requirement GetRequirement(int id)
{
return (from result in context.Requirement
where result.Id == id
select result).SingleOrDefault();
}
My unit test code is
[TestMethod]
public void DeleteRequirementSuccessfully()
{
var requirements = new List<Requirement>
{
new Requirement {
Id = 1,
Title = "Requirement 1",
Description = "Requirement 1 description"
},
new Requirement {
Id = 2,
Title = "Requirement 2",
Description = "Requirement 2 description"
},
new Requirement {
Id = 3,
Title = "Requirement 3",
Description = "Requirement 3 description"
}
}
.AsQueryable();
var mockDbSet = new Mock<DbSet<Requirement>>();
var context = new Mock<RequirementsDatabaseEntities>();
mockDbSet.As<IQueryable<Requirement>>()
.Setup(x => x.Provider)
.Returns(requirements.Provider);
mockDbSet.As<IQueryable<Requirement>>()
.Setup(x => x.ElementType)
.Returns(requirements.ElementType);
mockDbSet.As<IQueryable<Requirement>>()
.Setup(x => x.Expression)
.Returns(requirements.Expression);
mockDbSet.As<IQueryable<Requirement>>()
.Setup(x => x.GetEnumerator())
.Returns(requirements.GetEnumerator());
context.Setup(x => x.Requirement).Returns(mockDbSet.Object);
var dataAccess = new RequirementsDataAccess(context.Object);
int idToDelete = 1;
dataAccess.DeleteRequirement(idToDelete);
context.VerifyGet(x => x.Requirement, Times.Exactly(2)); // <- now verification is correct
mockDbSet.Verify(x => x.Remove(It.IsAny<Requirement>()), Times.Once());
context.Verify(x => x.SaveChanges(), Times.Once());
}
The test fails on the context.VerifyGet statement with the following error
Test method DataAccessTest.RequirementUnitTest+DeleteRequirement.DeleteRequirementSuccessfully threw exception:
System.InvalidOperationException: No connection string named
'RequirementsDatabaseEntities' could be found in the application config file.
If I comment out the context.VerifyGet line the test passes, but the
requirement is not deleted from the list. Does anyone have any idea why?
The test fails
And why when I comment out the offending line, it passes but the requirement
has not been deleted.
Why isn't this working?
First edit your definition of requirements to be a List<Requirement> not a Queryable to be able to mocking add or remove. And use requirements.AsQueryable() in Setup methods.
Second add this code to mocking remove:
mockDbSet.Setup(m => m.Remove(It.IsAny<Requirement>())).Callback<Requirement>((entity) => requirements.Remove(entity));
So you can check the count of your requirements list after removing.
Your code should be like this:
[TestMethod]
public void DeleteRequirementSuccessfully()
{
var requirements = new List<Requirement>
{
new Requirement {
Id = 1,
Title = "Requirement 1",
Description = "Requirement 1 description"
},
new Requirement {
Id = 2,
Title = "Requirement 2",
Description = "Requirement 2 description"
},
new Requirement {
Id = 3,
Title = "Requirement 3",
Description = "Requirement 3 description"
}
};
var mockDbSet = new Mock<DbSet<Requirement>>();
var context = new Mock<RequirementsDatabaseEntities>();
// You should use .AsQueryable() in these lines
mockDbSet.As<IQueryable<Requirement>>()
.Setup(x => x.Provider)
.Returns(requirements.AsQueryable().Provider);
mockDbSet.As<IQueryable<Requirement>>()
.Setup(x => x.ElementType)
.Returns(requirements.AsQueryable().ElementType);
mockDbSet.As<IQueryable<Requirement>>()
.Setup(x => x.Expression)
.Returns(requirements.AsQueryable().Expression);
mockDbSet.As<IQueryable<Requirement>>()
.Setup(x => x.GetEnumerator())
.Returns(requirements.GetEnumerator());
// This line should be added
mockDbSet.Setup(m => m.Remove(It.IsAny<Requirement>())).Callback<Requirement>((entity) => requirements.Remove(entity));
context.Setup(x => x.Requirement).Returns(mockDbSet.Object);
var dataAccess = new RequirementsDataAccess(context.Object);
int idToDelete = 1;
dataAccess.DeleteRequirement(idToDelete);
context.VerifyGet(x => x.Requirement, Times.Exactly(2));
//mockDbSet.Verify(x => x.Remove(It.IsAny<Requirement>()), Times.Once());
context.Verify(x => x.SaveChanges(), Times.Once());
// add this Assert
Assert.AreEqual(requirement.Count, 2);
// or
Assert.IsFalse(requirement.Any(x => x.Id == idToDelete));
}
it fails because you can't mock non virtual method.
the same problem: RequirementsDatabaseEntities.Requirement is not virtual method than it provide different output in test method than you expected. it probably returns empty collection.
fix: make RequirementsDatabaseEntities.Requirement getter virtual
Partial Solution - I found that the exception was just misleading. It was giving me this exception as I had got the number of times the mocked property was called wrong. It should have been called twice, instead of once. That part works now. But I still do not understand why the entity is not being removed from the list. Is it because it is queryable?
Since Moq uses inheritance in order to replace method calls you can only mock virtual methods (or interfaces).
So either make the methods/properties you're trying to fake virtual or use Isolator/JustMock etc. that work using Jit weaving and can fake these methods.