I was trying to unit test my repository. I need to mock the Where Clause with some values.
I have tried the following
var parentClass = new ParentClass {id = 1};
var subClass = new SubClass
{
id=2,
ParentClassId = parentClass.id,
ParentClass = parentClass
}
var subSubClass = new SubSubClass
{
id =3,
SubClassId = subClass.id,
SubClass = subClass
}
var dbContext = MockRepository.GenerateMock<IDbContext>();
var subClassContext = MockRepository.GenerateMock<IDbSet<SubClass>>();
var subSubClassContext = MockRepository.GenerateMock<IDbSet<SubSubClass>>();
subClassContext.Stub(x => x.GetEnumerator())
.Return(null)
.WhenCalled(c => c.ReturnValue = new List<SubClass> { subClass }.GetEnumerator());
subSubClassContext.Stub(x => x.GetEnumerator())
.Return(null)
.WhenCalled(c => c.ReturnValue = new List<SubSubClass> { subSubClass }.GetEnumerator());
I am testing the following code
var existingSubSubClasses = context.SubSubClass.Where(cba => cba.SubClass.ParentClassId == parentClassId).ToList();
I am getting ArgumentNullReferenceException
What am I doing wrong?
You should also stub context.SubSubClass property -- seems like it returns null by default.
Related
I would like to do a Mock Test and define as below :
public interface INode {
public int Id { get; set; }
public string NodeName { get; set; }
public IEnumerable<INode> Childrens { get; set; }
}
public interface INodeQuery {
public IEnumerable<INode> GetNodes();
}
public class NodeProcessService {
readonly INodeQuery nodeQuery;
public NodeProcessService(INodeQuery nodeQuery) {
this.nodeQuery = nodeQuery;
}
public string currentNodeName { get;set;}
public int Handler() {
var getNode = nodeQuery.GetNodes()
.Select(p => p.Childrens.FirstOrDefault(c => c.NodeName == currentNodeName))
.FirstOrDefault(p => p != null);
//do something...
}
}
In the test, I want to do the Mock nodeQuery which any expression will be return fixure value, such like this:
public NodeServiceTests()
{
fixture.Customize(new AutoMoqCustomization());
nodeQuery = fixture.Freeze<Mock<INodeQuery>>();
sut = fixture.Create<NodeProcessService>();
}
[Fact]
public void SimpleTest()
{
var fakeNode = fixture.Create<INode>();
nodeQuery.Setup(s => s.GetNodes().FirstOrDefault(It.IsAny<Func<INode, bool>>())).Returns(fakeNode);
var result = sut.Handler();
}
but I've got error as below code :
nodeQuery.Setup(s => s.GetNodes().FirstOrDefault(It.IsAny<Func<INode, bool>>())).Returns(fakeNode)
or
nodeQuery.Setup(s => s.GetNodes().FirstOrDefault()).Returns(fakeNode)
Can you advice how to do it , which I want to mock nodeQuery.GetNodes() whatever any expression func return a single fixture value.
Thank you for all advise,
You wish to escape or ignore parameters passed to Select and FirstOrDefault method. That wouldn't be possible until you mock the behavior of Select and FirstOrDefault method of IEnumerable<INode>.
It is easier to setup the mock data which can give you desired result even after execution of the real Select and FirstOrDefault methods.
Following is the mock data I came up with which you can set as a result of GetNodes method.
[Fact]
public void SimpleTest()
{
var node = new Node { Id = 1, NodeName = "parent" };
var child = new Node {Id =11, NodeName="main" };
node.Childrens = new List<INode>{child};
var nodes = new List<INode> {node};
nodeQuery.Setup(s => s.GetNodes()).Returns(nodes);
var result = sut.Handler();
}
Edit : Based on your feedback about currentNodeName not being static in FirstOrDefault method, I suggest following test approach.
You should not try to fake or setup LINQ methods. They are extension methods. They do not belong to any interface or class. So faking them or setting up their bhehavior will not work at all.
Also you are testing the code of NodeProcessService class. You should not fake any part of it's code. Only dependency behavior should be faked. If you fake the NodeProcessService code, that means you are not actually unit testing real code and its behavior but you are testing the fake code.
You have currentNodeName property in NodeProcessService class. And value of this property is used in FirstOrDefault criteria of p.Childrens.
So when you run the test, you should set currentNodeName property value and use the same value in creating fake nodes too. This will make sure that the logic of Handler method is executed as exactly it is written.
// this test is to call Handler method and it should return the
// children nodes whose name is "main".
[Fact]
public void TestChildNodesReturnWhenPresent()
{
var currentNodeName = "main"; //this can be any thing you want.
sut.currentNodeName = currentNodeName;
var node = new Node { Id = 1, NodeName = "parent" };
var child = new Node {Id =11, NodeName= currentNodeName };
node.Childrens = new List<INode>{child};
var nodes = new List<INode> {node};
nodeQuery.Setup(s => s.GetNodes()).Returns(nodes);
var result = sut.Handler();
Assert.IsNotNull(result);
}
// this test is to call Handler method and it should return null
// when children not with specified name does not exist.
[Fact]
public void TestNullReturnedWhenChildreNodeNotPresent()
{
var currentNodeName = "main"; //this can be any thing you want.
sut.currentNodeName = currentNodeName;
var node = new Node { Id = 1, NodeName = "parent" };
var child = new Node {Id =11, NodeName= "childNode" };
node.Childrens = new List<INode>{child};
var nodes = new List<INode> {node};
nodeQuery.Setup(s => s.GetNodes()).Returns(nodes);
var result = sut.Handler();
Assert.IsNull(result);
}
As Chetan wrote in the comments, you should mock only GetNodes():
nodeQuery.Setup(s => s.GetNodes()).Returns(new[] { fakeNode });
The mock will return a collection consisting of only the fakeNode.
I'm trying to write unit test using xUnit for EntityService class which is using Dapper to get data from Sqllite database. In my unit test it always returns actual values as List<Entity> [] and test fails. I'm not understanding what I am missing here.
Test Class
public class EntityServiceTests
{
private readonly IEntityService _sut;
private readonly Mock<IEntityService> _entityServiceMock;
public EntityServiceTests()
{
_entityServiceMock = new Mock<IEntityService>();
var dapperMock = new Mock<IDapperWrapper>();
_sut = new EntityService(dapperMock.Object);
}
[Fact]
public void GetEntities_ShouldReturnEntities()
{
//Arrange
var expectedEntities = new List<Entity>
{
new()
{
Id = 1,
Name = "Test",
X = 12,
Y = 14.5,
CoordId = 1
},
new()
{
Id = 2,
Name = "Test2",
X = 16,
Y = 18.5,
CoordId = 2
}
};
var query = #"SELECT ent.*, crd.x, crd.y, crd.id as CoordId
FROM entities ent
INNER JOIN coords crd ON crd.entityId = ent.Id";
_entityServiceMock.Setup(x => x.GetEntities(0)).Returns(expectedEntities);
//Act
var entities = _sut.GetEntities(0).ToList();
//Assert
Assert.Equal(expectedEntities, entities);
}
}
Service Class
public class EntityService : IEntityService
{
private readonly IDapperWrapper _dapperWrapper;
public EntityService(IDapperWrapper dapperWrapper)
{
_dapperWrapper = dapperWrapper;
}
public IEnumerable<Entity> GetEntities(int entityId)
{
var query = #"SELECT ent.*, crd.x, crd.y, crd.id as CoordId
FROM entities ent
INNER JOIN coords crd ON crd.entityId = ent.Id ";
if (entityId > 0)
{
query += " WHERE ent.id = #id";
var entities = _dapperWrapper.Query<Entity>(query, new { id = entityId });
return entities;
}
else
{
var entities = _dapperWrapper.Query<Entity>(query);
return entities;
}
}
}
Dapper Wrapper Class
public class DapperWrapper : IDapperWrapper
{
private IDbConnection Connection { get; }
public DapperWrapper()
{
Connection = new SQLiteConnection(GetConnectionString("ConnectionString"));
}
private string GetConnectionString(string name)
{
return ConfigurationManager.ConnectionStrings[name].ConnectionString;
}
public IEnumerable<T> Query<T>(string query)
{
return Connection.Query<T>(query);
}
public IEnumerable<T> Query<T>(string query, object param)
{
return Connection.Query<T>(query, param);
}
public T QuerySingle<T>(string query, object param)
{
return Connection.QuerySingle<T>(query, param);
}
}
Normally the project is working fine. but in Test it fails. I think i'm missing something very basic but crucial.
UPDATE: I'm using this code now but still getting failed result
[Fact]
public void GetEntities_Should_Return_All_Entities_If_0_Is_Provided_In_Param()
{
//Arrange
var expectedEntities = new List<Entity>
{
new()
{
Id = 1,
Name = "Test",
X = 12,
Y = 14.5,
CoordId = 1
},
new()
{
Id = 2,
Name = "Test2",
X = 16,
Y = 18.5,
CoordId = 2
}
};
var query = #"SELECT ent.*, crd.x, crd.y, crd.id as CoordId
FROM entities ent
INNER JOIN coords crd ON crd.entityId = ent.Id ";
var dapperMock = new Mock<IDapperWrapper>();
dapperMock.Setup(x => x.Query<Entity>(query)).Returns(expectedEntities);
var sut = new EntityService(dapperMock.Object);
//Act
var entities = sut.GetEntities(0);
//Assert
Assert.Equal(expectedEntities, entities);
}
I think i'm missing something very basic but crucial.
Indeed 🙂 mocking is intended to be used to mock away the dependencies from a unit to test (sut). In your case your unit to test is the EntityService and the dependency to mock away is IDapperWrapper.
But instead of only mocking the dependency, you're mocking the SUT as well with _entityServiceMock.
So you COULD try to do it like this within your test:
public class EntityServiceTests
{
[Fact]
public void GetEntities_ShouldReturnEntities()
{
//Arrange
var expectedEntities = new List<Entity>
{
new()
{
Id = 1,
Name = "Test",
X = 12,
Y = 14.5,
CoordId = 1
}
};
var query = #"SELECT ent.*, crd.x, crd.y, crd.id as CoordId
FROM entities ent
INNER JOIN coords crd ON crd.entityId = ent.Id WHERE ent.id = #id";
var dapperMock = new Mock<IDapperWrapper>();
dapperMock.Setup(x => x.Query<Entity>(query, 1)).Returns(expectedEntities.First());
var sut = new EntityService(dapperMock.Object);
//Act
var entities = sut.GetEntities(1).ToList();
//Assert
Assert.Equal(expectedEntities, entities);
}
}
But I highly discourage you from doing so because you'll end up mocking all the Dapper stuff.
Instead you better use an in-memory database (like SQLite), use a real Dapper instance. This way your tests will become much more comprehensive, shorter and business-facing. This blog post should give you a good starting point.
I'm using the moq framework by Daniel Cazzulino, kzu Version 4.10.1.
I want to moq so i can test a particular part of functionality (below is the simplistic version of the Code i could extract)
The fluent/chain method so are designed so you can get object by an Id and include any additional information if required.
i'm having some trouble fetching the correct object when the function is calling the moq'ed method, which is currently returning the last moq'ed object which is wrong
/*My current Moq setup*/
class Program
{
static void Main(string[] args)
{
var mock = new Mock<IFluent>();
var c1 = new ClassA() { Id = 1, Records = new List<int>() { 5, 2, 1, 10 }, MetaData = new List<string>() };
var c2 = new ClassA() { Id = 2, Records = new List<int>(), MetaData = new List<string>() { "X", "Y", "Z" } };
mock.Setup(x => x.GetById(1).IncludeRecords().IncludeMetaData().Get()).Returns (c1);
mock.Setup(x => x.GetById(2).IncludeRecords().IncludeMetaData().Get()).Returns(c2);
var result = new ComputeClass().ComputeStuff(mock.Object);
Console.WriteLine(result);
Console.ReadLine();
}
}
/*Fluent interface and object returned*/
public interface IFluent
{
IFluent GetById(int id);
IFluent IncludeRecords();
IFluent IncludeMetaData();
ClassA Get();
}
public class ClassA
{
public int Id { get; set; }
public ICollection<int> Records { get; set; }
public ICollection<string> MetaData { get; set; }
}
/*the method which is doing the work*/
public class ComputeClass
{
public string ComputeStuff(IFluent fluent)
{
var ids = new List<int>() { 1, 2 };
var result = new StringBuilder();
foreach (var id in ids)
{
var resClass = fluent.GetById(id).IncludeRecords().IncludeMetaData().Get();
result.Append($"Id : {id}, Records: {resClass.Records.Count}, MetaData: {resClass.MetaData.Count}{Environment.NewLine}");
}
return result.ToString();
}
}
Current incorrect result
/*Id : 1, Records: 0, MetaData: 3
Id : 2, Records: 0, MetaData: 3*/
Expected Result
/*Id : 1, Records: 3, MetaData: 0
Id : 2, Records: 0, MetaData: 3*/
The easiest way would be to split out each setup:
var mock = new Mock<IFluent>();
var mock1 = new Mock<IFluent>();
var mock2 = new Mock<IFluent>();
mock.Setup(x => x.GetById(1)).Returns(mock1.Object);
mock1.Setup(x => x.IncludeRecords()).Returns(mock1.Object);
mock1.Setup(x => x.IncludeMetaData()).Returns(mock1.Object);
mock1.Setup(x => x.Get()).Returns(c1);
mock.Setup(x => x.GetById(2)).Returns(mock2.Object);
mock2.Setup(x => x.IncludeRecords()).Returns(mock2.Object);
mock2.Setup(x => x.IncludeMetaData()).Returns(mock2.Object);
mock2.Setup(x => x.Get()).Returns(c2);
var result = new ComputeClass().ComputeStuff(mock.Object);
You could create an extension/utility to handle this all for you if you wanted something a bit more complex, take a look at this blog post: https://www.codemunki.es/2014/11/20/mocking-a-fluent-interface-automatically-in-moq/
Just an addition to the already existing answer. For mocking fluent API there is one usefull option within the moq, it is SetReturnsDefault, it could save some mocking especially if you have huge fluent API, e.g.
var mock = new Mock<IFluent>();
var mock1 = new Mock<IFluent>();
var mock2 = new Mock<IFluent>();
mock.Setup(x => x.GetById(1)).Returns(mock1.Object);
mock1.SetReturnsDefault(mock1.Object);
mock1.Setup(x => x.Get()).Returns(a);
mock.Setup(x => x.GetById(2)).Returns(mock2.Object);
mock2.SetReturnsDefault(mock2.Object);
mock2.Setup(x => x.Get()).Returns(b);
var aa = mock.Object.IncludeMetaData().GetById(1).IncludeMetaData().Get();
var bb = mock.Object.IncludeMetaData.GetById(2).IncludeMetaData.Get();
With this approach you actually have to mock only method which differ but not the all methods from fluent API.
I need to test logic that executes a function, after which it changes a property on the parameter and then executes the same function with the updated parameter.
To help illustrate this, here is some sample code:
Interface:
public interface IWorker
{
MyObjectB DoWork(MyObject myObject);
}
MyObjectB:
public class MyObjectB
{
public string Message { get; set; }
}
Implementation:
public MyObjectB DoWork(IWorker worker, MyObject myObject)
{
worker.DoWork(myObject);
myObject.Name = "PersonB";
worker.DoWork(myObject);
return new MyObjectB() { Message = "Done" };
}
Test:
public void RhinoMocksSampleTest()
{
var workerStub = MockRepository.GenerateStub<IWorker>();
workerStub.Stub(n => n.DoWork(Arg<MyObject>.Is.Anything));
var myObj = new MyObject { Id = 1, Name = "PersonA" };
var p = new Program();
p.DoWork(workerStub, myObj);
workerStub.AssertWasCalled(d => d.DoWork(Arg<MyObject>.Matches(r => r.Name == "PersonA")));
workerStub.AssertWasCalled(d => d.DoWork(Arg<MyObject>.Matches(r => r.Name == "PersonB")));
}
The first AssertWasCalled fails because the value is ‘PersonB’.
Is there a function/call I can use to test the state of the object for the first call?
Here's how I would do what you're trying to do:
public void RhinoMocksSampleTest()
{
var workerMock = MockRepository.GenerateMock<IWorker>();
workerMock.Expect(d => d.DoWork(Arg<MyObject>.Matches(r => r.Name == "PersonA")));
workerMock.Expect(d => d.DoWork(Arg<MyObject>.Matches(r => r.Name == "PersonB")));
var myObj = new MyObject { Id = 1, Name = "PersonA" };
var p = new Program();
p.DoWork(workerMock , myObj);
workerMock.VerifyAllExpectations();
}
In addition to nice answer what aprescott has provided I can show another one approach which could be useful in some situations:
The idea is to manually store values which you are interesting in into some collection. Then you will be able to assert that collection contains required sequense.
public void MyTest()
{
// that is list which will contain passed names
var actualNames = new List<string>();
// stub only saves passed Name property into list
var workerStub = MockRepository.GenerateStub<IWorker>();
workerStub
.Stub(w => w.DoWork(Arg<MyObject>.Is.Anything))
.Do((Action<MyObject>)(mo => actualNames.Add(mo.Name)));
var myObject = new MyObject { Name = "PersonA" };
var target = new MyWorker();
target.DoWork(workerStub, myObject);
// here we do assert that names list contains what is required
Assert.That(actualNames, Is.EqualTo(new[] { "PersonA", "PersonB" }));
}
PS. Yeah, it works for case when you need check that calls order is correct :)
I have a service layer between my app and the mongo database.
I'm trying to build a unit test using moq
I'm quite new to moq so I started with what I thought would be a trivial test.
Code to test:
public List<BsonDocument> GetAllSettings()
{
var collection = MongoDatabase.GetCollection<BsonDocument>("Settings");
var query = from e in collection.AsQueryable()
select e;
var settings = query.ToList();
return settings;
}
Where:
Settings is a Collection
MongoDatabase is a MongoDBDriver.MongoDatabase
I've tried this as my test:
[Test()]
public void GetAllSettingsTest()
{
//Arrange
BsonDocument doc01 = new BsonDocument();
BsonDocument doc02 = new BsonDocument();
var mongoDatabase = new Mock<MongoDatabase>();
var collection = new Mock<MongoCollection<BsonDocument>>();
mongoDatabase.Setup(f => f.GetCollection(MongoCollection.Settings)).Returns(collection.Object);
collection.Object.Insert(doc01);
collection.Object.Insert(doc02);
ILogger logger = new Logger();
DatabaseClient.DatabaseClient target = new DatabaseClient.DatabaseClient(logger);
target.MongoDatabase = mongoDatabase.Object;
MongoCursor<BsonDocument> cursor = collection.Object.FindAllAs<BsonDocument>();
List<BsonDocument> expected = cursor.ToList();
List<BsonDocument> actual;
//Act
actual = target.GetAllSettings();
//Assert
Assert.AreEqual(expected, actual);
}
I'm getting an error of "Could not find a parameterless constructor" at:
mongoDatabase.Setup(f => f.GetCollection(MongoCollections.Settings)).Returns(collection.Object);
The error refers to the MongoCollection object. I didn't think it had a constructor.
What can I do to get my test to run?
this question is most probably related to: How do I mock MongoDB objects to test my data models?
Anyway, here is minimal Moq configuration required to mock
var message = string.Empty;
var serverSettings = new MongoServerSettings()
{
GuidRepresentation = MongoDB.Bson.GuidRepresentation.Standard,
ReadEncoding = new UTF8Encoding(),
ReadPreference = new ReadPreference(),
WriteConcern = new WriteConcern(),
WriteEncoding = new UTF8Encoding()
};
var server = new Mock<MongoServer>(serverSettings);
server.Setup(s => s.Settings).Returns(serverSettings);
server.Setup(s => s.IsDatabaseNameValid(It.IsAny<string>(), out message)).Returns(true);
var databaseSettings = new MongoDatabaseSettings()
{
GuidRepresentation = MongoDB.Bson.GuidRepresentation.Standard,
ReadEncoding = new UTF8Encoding(),
ReadPreference = new ReadPreference(),
WriteConcern = new WriteConcern(),
WriteEncoding = new UTF8Encoding()
};
var database = new Mock<MongoDatabase>(server.Object, "test", databaseSettings);
database.Setup(db => db.Settings).Returns(databaseSettings);
database.Setup(db => db.IsCollectionNameValid(It.IsAny<string>(), out message)).Returns(true);
var mockedCollection = collection.Object;
Anyway, as I mentioned in linked question, this might not be useful when any of inner-workings of MongoDriver change.
I'm not familiar with the MongoDbDriver.MongoDatabase, but if it works like I think it does, then you can't mock it directly. You need to abstract the MongoDB access code, and mock that. That would be an actual unit test. e.g.
public interface IMongoDBRepository
{
Collection<T> GetCollection<T>(string name) where T BsonDocument;
}
public class MongoDbRepository : IMongoDBRepository
{
public Collection<T> GetCollection<T>(string name)
where T : BsonDocument
{
return MongoDatabase.GetCollection<BsonDocument>(name);
}
}
Now, in your code, you inject an IMongoDBRepository (using whatever DI method you like) and your code would looks something like this:
private IMongoDBRepository _mongoDBRepository; //this gets injected
public List<BsonDocument> GetAllSettings()
{
var collection = _mongoDBRepository.GetCollection<BsonDocument>("Settings");
var query = from e in collection.AsQueryable()
select e;
var settings = query.ToList();
return settings;
}
And finally your unit test:
[Test()]
public void GetAllSettingsTest()
{
//Arrange
BsonDocument doc01 = new BsonDocument();
BsonDocument doc02 = new BsonDocument();
var mongoDatabase = new Mock<IMongoDBRepository>();
var collection = new Mock<MongoCollection<BsonDocument>>();
mongoDatabase.Setup(f => f.GetCollection(MongoCollection.Settings)).Returns(collection.Object);
collection.Object.Insert(doc01);
collection.Object.Insert(doc02);
//rest of test
}