How would I use moq to test a MongoDB service layer? - c#

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
}

Related

Mock IOptionsMonitor

How can I make an class instance manually of a class that requires an IOptionsMonitor in the constructor?
My Class
private readonly AuthenticationSettings _authenticationSettings;
public ActiveDirectoryLogic(IOptionsMonitor<AuthenticationSettings> authenticationSettings)
{
_authenticationSettings = authenticationSettings.CurrentValue;
}
My test
AuthenticationSettings au = new AuthenticationSettings(){ ... };
var someOptions = Options.Create(new AuthenticationSettings());
var optionMan = new OptionsMonitor(someOptions); // dont work.
ActiveDirectoryLogic _SUT = new ActiveDirectoryLogic(au);
I tried to make an IOptionsMonitor object manually but can't figure out how.
You are calling the constructor of the OptionsMonitor<TOptions> class incorrectly.
In this case I would have just mocked the IOptionsMonitor<AuthenticationSettings> interface
For example using Moq
AuthenticationSettings au = new AuthenticationSettings() { ... };
var monitor = Mock.Of<IOptionsMonitor<AuthenticationSettings>>(_ => _.CurrentValue == au);
ActiveDirectoryLogic _SUT = new ActiveDirectoryLogic(monitor);
Here is another way to do it that doesn't involve trying to set the readonly CurrentValue field.
using Moq;
private IOptionsMonitor<AppConfig> GetOptionsMonitor(AppConfig appConfig)
{
var optionsMonitorMock = new Mock<IOptionsMonitor<AppConfig>>();
optionsMonitorMock.Setup(o => o.CurrentValue).Returns(appConfig);
return optionsMonitorMock.Object;
}
Achieving the same in NSubstitute:
var optionsMonitorMock = Substitute.For<IOptionsMonitor<AuthenticationSettings>>();
optionsMonitorMock.CurrentValue.Returns(new AuthenticationSettings
{
// values go here
});

How to mock nested properties and objects and their functions?

I have the code below which I would like to test, but I'm not sure whether it is possible or not.
I have EF repositories and they are put together to a class as public properties. I don't know exactly whether it is bad solution or not, but it is easier to manage the code and its dependencies. Only the testability is still a question.
Purpose of my test is injecting data via
administrationRepository.ModuleScreen.GetAll()
method and catch the result. I know that it can be tested once it is deployed, but I want the tests in build time in order to have as fast feedback as possible.
I went through questions and answers here, but I cannot find answers. In my code I got to the point where the property is set up, but when I call the administrationRepoMock.Object.ModuleScreen.GetAll() ReSharper offers only the methods coming from Entitiy Framework and not the Moq related functions.
It is possible what I want? If so, how? Is my design suitable for this? If not can you give me articles, urls where I can see examples?
Repository:
public interface IModuleScreen
{
IEnumerable<DomainModel.Administration.ModuleScreen> GetAll();
}
public interface IAdministrationRepository
{
IModuleScreen ModuleScreen { get; }
}
public partial class AdministrationRepository : IAdministrationRepository
{
public virtual IModuleScreen ModuleScreen { get; private set; }
public AdministrationRepository( IModuleScreen moduleScreen )
{
this.ModuleScreen = moduleScreen;
}
}
Application:
public partial class DigitalLibraryApplication : IDigitalLibraryApplication
{
private IAdministrationRepository _administrationRepository;
private IMapper.IMapper.IMapper _mapper;
private IDiLibApplicationHelper _dilibApplicationHelper;
#region Ctor
public DigitalLibraryApplication( IAdministrationRepository administrationRepository, IMapper.IMapper.IMapper mapper, IDiLibApplicationHelper diLibApplicationHelper)
{
_administrationRepository = administrationRepository;
_mapper = mapper;
_dilibApplicationHelper = diLibApplicationHelper;
}
#endregion
public IEnumerable<ModuleScreenContract> GetModuleScreens()
{
//inject data here
IEnumerable<ModuleScreen> result = _administrationRepository.ModuleScreen.GetAll();
List<ModuleScreenContract> mappedResult = _mapper.MapModuleScreenToModuleScreenContracts(result);
return mappedResult;
}
}
Test code:
[Test]
public void ItCalls_ModuleRepository_Get_Method()
{
List<SayusiAndo.DiLib.DomainModel.Administration.ModuleScreen> queryResult = new List<SayusiAndo.DiLib.DomainModel.Administration.ModuleScreen>()
{
new DomainModel.Administration.ModuleScreen()
{
Id = 100,
},
};
var moduleScreenMock = new Mock<IModuleScreen>();
moduleScreenMock.Setup(c => c.GetAll()).Returns(queryResult);
administrationRepoMock.SetupProperty(c => c.ModuleScreen, moduleScreenMock.Object);
var mapperMock = new Mock<IMapper.IMapper.IMapper>();
var dilibApplicationHerlperMock = new Mock<IDiLibApplicationHelper>();
IDigitalLibraryApplication app = new DigitalLibraryApplication( administrationRepoMock.Object, mapperMock.Object, dilibApplicationHerlperMock.Object );
app.GetModules();
//issue is here
administrationRepoMock.Object.ModuleScreen.GetAll() //???
}
Here is a refactoring of your test that passes when run. You can update the pass criteria to suit you definition of a successful test.
[Test]
public void ItCalls_ModuleRepository_Get_Method() {
// Arrange
List<ModuleScreen> queryResult = new List<ModuleScreen>()
{
new ModuleScreen()
{
Id = 100,
},
};
//Building mapped result from query to compare results later
List<ModuleScreenContract> expectedMappedResult = queryResult
.Select(m => new ModuleScreenContract { Id = m.Id })
.ToList();
var moduleScreenMock = new Mock<IModuleScreen>();
moduleScreenMock
.Setup(c => c.GetAll())
.Returns(queryResult)
.Verifiable();
var administrationRepoMock = new Mock<IAdministrationRepository>();
administrationRepoMock
.Setup(c => c.ModuleScreen)
.Returns(moduleScreenMock.Object)
.Verifiable();
var mapperMock = new Mock<IMapper>();
mapperMock.Setup(c => c.MapModuleScreenToModuleScreenContracts(queryResult))
.Returns(expectedMappedResult)
.Verifiable();
//NOTE: Not seeing this guy doing anything. What's its purpose
var dilibApplicationHerlperMock = new Mock<IDiLibApplicationHelper>();
IDigitalLibraryApplication app = new DigitalLibraryApplication(administrationRepoMock.Object, mapperMock.Object, dilibApplicationHerlperMock.Object);
//Act (Call the method under test)
var actualMappedResult = app.GetModuleScreens();
//Assert
//Verify that configured methods were actually called. If not, test will fail.
moduleScreenMock.Verify();
mapperMock.Verify();
administrationRepoMock.Verify();
//there should actually be a result.
Assert.IsNotNull(actualMappedResult);
//with items
CollectionAssert.AllItemsAreNotNull(actualMappedResult.ToList());
//There lengths should be equal
Assert.AreEqual(queryResult.Count, actualMappedResult.Count());
//And there should be a mapped object with the same id (Assumption)
var expected = queryResult.First().Id;
var actual = actualMappedResult.First().Id;
Assert.AreEqual(expected, actual);
}

Unit test won't "cover" simple get method. (c#)

I have a simple "Get" method. Ex:
public class Foo : IFoo
{
public Dictionary<string,string> GetSomething(string xyz)
{
var result = new Dictionary<string,string>
... Go to DB and return some key value pairs
return result;
}
}
I wrote a simple test that execute and passes successfully but I'm not getting code coverage on the method.
[TestMethod()]
public void GetSomething()
{
var target = new StubIFoo();
var expected = new Dictionary<string, string>
{
{"blahKey","blahValue"}
};
var results = target.GetSomethingString = s =>
{
var result = new Dictionary<string, string> {{"a", "b"}};
return result;
};
var actual = results("a");
CollectionAssert.AreEqual(expected,actual);
}
I also tried to target the class itself, which provides the coverage but doesn't return any results (ex: "var target = new StubFoo();")
Again, it successfully executes and passes but I'm not getting any coverage. Any pointers would be appreciated. Thanks.
Foo.GetSomething() has 0 code coverage, because you never call it in your test.
Instead, you call StubIFoo.GetSomething().
Change var target = new StubIFoo(); into var target = new Foo();, remove the code initializing StubIFoo and you will get some coverage.
Stubs are there to prevent you from using (and testing) the real class. But you must not use a stub of the class you are testing !
In your test you are not calling the method GetSomething, but instead are setting a value to the property GetSomethingString.
// Here is the problem. This:
var results = target.GetSomethingString = s =>
{
var result = new Dictionary<string, string> {{"a", "b"}};
return result;
};
// Is equal to this:
var lambda = s =>
{
var result = new Dictionary<string, string> {{"a", "b"}};
return result;
};
var results2 = target.GetSomethingString = lambda;
Here is general idea what you should do
public class Foo : IFoo
{
IDbAccess db;
// Pass the interface, do pass parameters to create it inside constructor
public Foo(IDbAccess db)
{
this.db = db;
}
public Dictionary<string,string> GetSomething(string xyz)
{
var result = new Dictionary<string,string>
// ... Go to DB and return some key value pairs
result.Add(db.MethodWhatever(xyz));
return result;
}
}
[TestMethod()]
public void GetSomething()
{
var dbMock = new DatabaseMock(); // This implements IDbAccess
var target = new Foo(dbMock);
var expected = new Dictionary<string, string>
{
{"blahKey","blahValue"}
};
// get something
var results = target.GetSomething("xyzstring");
// verify results
var actual = results.whatever;
CollectionAssert.AreEqual(expected,actual);
}

RhinoMock Stub Linq Where clause for DbContext

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.

Having trouble getting method on mocked object to return fake data

I am trying to write a test for the "MethodToTest" like shown below
Public Class UserService()
{
private IRepository<User> _userRepo;
public UserService(IRepository<User> userRepo = null)
{
_userRepo = userRepo ?? new UserRepository();
}
public List<string> MethodToTest(string userName)
{
var user = _userRepo.Find(u => u.Email == userName).First<User>();
//Other stuff that eventually returns a List<string>
}
}
I have the following in my test
[Test]
public void GetItemsByUserName_UserName_ListOfItems()
{
var userName = "AnyString";
var fakeUserRepo = new Mock<IRepository<User>>();
var fakeUserList = new List<User>()
{
new User()
{
Email = userName,
Roles = new List<Role>()
{
new Role()
{
Name="Role1"
},
new Role()
{
Name="Role2"
}
}
}
};
var fakeUserListQueryable = fakeUserList.AsQueryable<User>();
var query = new Func<User, bool>(u => u.Email == userName);
fakeUserRepo.Setup(u => u.Find(query)).Returns(fakeUserListQueryable);
var userService = new UserService(fakeUserRepo.Object);
var menu = userService.GetMenuByUserName(userName);
//Assert Something
}
The problem is that I can't get the find method of the _userRepo to return my fake list of users.
When running the test I get a "Sequence Contains No Elements" when executing
_userRepo.Find(u => u.Email == userName).First<User>();
in the MethodToTest.
What am I doing wrong?
I'm thinking that you have an equality issue on the Func<User, bool>. As you know, Moq will setup the fakeUserRepo if the query equals the actual Func inside the code you are calling. However, you are creating a new Func<User, bool> in your setup code. So, when Moq checks equality, it is checking between two different reference types and therefore not setting up the expectation.
I would try something like this:
fakeUserRepo.Setup(u => u.Find(It.IsAny<Func<User, bool>>())).Returns(fakeUserListQueryable);
See if that works and then add the username back in.

Categories