I am trying to figure out how or if it is possible to do the following with Moq
public class Download
{
private IFoo ifoo;
public Download(IFoo ifoo)
{
this.ifoo = ifoo;
}
public void Download()
{
var files = Directory.GetFiles("filepath"); //<<<===
foreach (var item in files)
{
// do something
}
}
}
In unit test.
// Arrange
var mockFoo = new Mock<IFoo>();
mockFoo.setup( s => s.Bar()).returns(true);
var foo = new Foo(mockFoo.Object);
// Act
foo.Download()
How can I mock the files variable, so the method uses the mock version. Is this even the correct approach? As I am not mocking the class, and rather mocking the dependency how do I go about settings the files variable so it looks at mocked file string[].
You would need to depend on an abstraction to get your files instead of having a hard dependency on System.IO.Directory:
public interface IFileProvider
{
string[] GetFiles(string path);
}
public class PhysicalFileProvider : IFileProvider
{
public string[] GetFiles(string path)
{
return Directory.GetFiles(path);
}
}
You would inject the abstraction in exactly the same way as you're injecting IFoo.
Now you can mock IFileProvider using Moq, creating a mock that returns exactly the strings that you want it to return.
var fileProvider = new Mock<IFileProvider>();
fileProvider.Setup(x => x.GetFiles(It.IsAny<string>()))
.Returns(new[] {"file1.txt", "file2.txt"});
You can also use Microsoft.Extensions.FileProviders.Physical which provides both the file system access and the abstraction.
public class Download
{
private readonly IFoo _foo;
private readonly Microsoft.Extensions.FileProviders.IFileProvider _fileProvider;
public Download(IFoo foo, IFileProvider fileProvider)
{
_foo = foo;
_fileProvider = fileProvider;
}
public void SomethingWithFiles()
{
var files = _fileProvider.GetDirectoryContents("filepath")
.Where(item => !item.IsDirectory);
foreach (var item in files)
{
// something
}
}
}
The concrete implementation would be PhysicalFileProvider.
One more variation. Instead of injecting an interface, inject a delegate:
public delegate string[] GetFilesFunction(string path);
public class Download
{
private readonly IFoo _foo;
private readonly GetFilesFunction _getFiles;
public Download(IFoo foo, GetFilesFunction getFiles)
{
_foo = foo;
_getFiles = getFiles;
}
...
That's even easier to mock. You don't even need Moq.
var subject = new Download(mockedFoo, path => new []{"file1.txt","file2.txt"} );
Related
I'm developing an API which communicates with MongoDB and I need to create some statistics from one collection. I have the following service:
public class BoxService : IBoxService
{
private readonly IMongoCollection<Box> _boxCollection;
public BoxService(IOptions<DbSettings> dbSettings, IMongoClient mongoClient)
{
var mongoDatabase = mongoClient.GetDatabase(dbSettings.Value.DatabaseName);
_boxCollection = mongoDatabase.GetCollection<Box>(dbSettings.Value.BoxCollectionName);
}
public async Task<List<BoxStatisticsDto>> GetBoxNumberStatisticsAsync()
{
var boxNumberStatisticsList = new List<BoxStatisticsDto>();
var results = await _boxCollection.AsQueryable()
.Select(box => new { box.WarehouseId, Content = box.Content ?? string.Empty })
.ToListAsync();
// More calculations with the results list
return boxNumberStatisticsList;
}
}
And the following test:
public class BoxServiceTest
{
private readonly IMongoCollection<Box> _boxCollection;
private readonly List<Box> _boxes;
private readonly IBoxService _boxService;
public BoxServiceTest()
{
_boxCollection = A.Fake<IMongoCollection<Box>>();
_boxes = new List<Box> {...};
var mockOptions = A.Fake<IOptions<DbSettings>>();
var mongoClient = A.Fake<IMongoClient>();
var mongoDb = A.Fake<IMongoDatabase>();
A.CallTo(() => mongoClient.GetDatabase(A<string>._, default)).Returns(mongoDb);
A.CallTo(() => mongoDb.GetCollection<Box>(A<string>._, default)).Returns(_boxCollection);
_boxService = new BoxService(mockOptions, mongoClient);
}
}
This is working so far, the BoxService is created with the fake parameters and I can test other functionalities of the service (FindAll, FindById, Create, etc.) but how can I test the GetBoxNumberStatisticsAsync function? I can't fake the AsQueryable because it's an extension method.
As you've noted, you can't fake an extension method. This question is asked every once in a while. For example, see Faking an Extension Method in a 3rd Party Library. There are a few approaches:
if the static method is simple enough, to divine what it does and fake the non-static methods that it calls
add a layer of indirection: wrap the call to the extension method in an interface that you can fake
don't fake the database. Instead, replace it with some in-memory analogue, if one exists (I don't know what's available for Mongo)
Here is what I ended up with. A base interface for all my services:
public interface IBaseService<T>
{
//generic method definitions for all services: Findall, FindById, Create, Update
}
An abstract class to have a generic constructor:
public abstract class BaseService<T> : IBaseService<T>
{
protected BaseService(IOptions<DbSettings> dbSettings, IMongoClient mongoClient, string collectionName)
{
var mongoDatabase = mongoClient.GetDatabase(dbSettings.Value.DatabaseName);
Collection = mongoDatabase.GetCollection<T>(collectionName);
}
protected IMongoCollection<T> Collection { get; }
// abstract method definitions for IBaseService stuff
public virtual async Task<List<T>> CollectionToListAsync()
{
return await Collection.AsQueryable().ToListAsync();
}
}
An interface for my BoxService:
public interface IBoxService : IBaseService<Box>
{
public Task<List<BoxStatisticsDto>> GetBoxNumberStatisticsAsync();
}
The service itself:
public class BoxService : BaseService<Box>, IBoxService
{
public BoxService(IOptions<DbSettings> dbSettings, IMongoClient mongoClient)
: base(dbSettings, mongoClient, dbSettings.Value.BoxCollectionName)
{
}
public async Task<List<BoxStatisticsDto>> GetBoxNumberStatisticsAsync()
{
var boxNumberStatisticsList = new List<BoxStatisticsDto>();
var list = await CollectionToListAsync();
var results = list.Select(box => new { box.WarehouseId, Content = box.Content ?? string.Empty }).ToList();
//...
return boxNumberStatisticsList;
}
}
And finally the test:
public async Task GetBoxNumberStatisticsAsync_ReturnsStatistics()
{
// Arrange
var expected = new List<BoxStatisticsDto> {...};
var fakeService = A.Fake<BoxService>(options => options.CallsBaseMethods());
A.CallTo(() => fakeService.CollectionToListAsync()).Returns(_boxes);
// Act
var boxList = await ((IBoxService)fakeService).GetBoxNumberStatisticsAsync();
// Assert
}
I'm not a huge fan of making the CollectionToListAsync public, but nothing really worked for me here. I tried creating IQueryable and IEnumerable from my list and convert them to IMongoQueryable but no success. I also tried faking the IMongoQueryable but I couldn't execute the Select on it as it gave an error that the 'collectionNamespace' can't be null and the CollectionNamespace can't be faked, because it's a sealed class.
I've been reading around and I can't seem to find a case that matches the behavior I want with Moq.
I want to mock a specific method (which is interfacing with an external API) of a class that I want to test. The problem is that, as I understand it, once the class is .Create<T>, you cannot .Setup()... any method on it.
Here is an example:
public class ClassA
{
public void ConfigureExpansion()
{
var classB = new ClassB();
var data = GetExternalData(); // I want to mock this
//data is used in the code
classB.TaskB(data); // I want to mock this
}
public string GetExternalData()
{
return data...
}
}
public class ClassB
{
public void TaskB(String myData)
{
//Does some work
}
}
[TestMethod]
public void Test()
{
using (var mock = AutoMock.GetLoose())
{
mock.Mock<IClassB>().Setup(x => x.TaskB(It.IsAny<string>()));
var cls = mock.Create<ClassA>();
cls.Setup(x => x.GetExternalData(It.IsAny<string>())).Return("MyData"); // <--- This is not valid, but represents what I am trying to do.
//act
cls.ConfigureExpansion();
mock.Mock<IClassB>().Verify(x => x.TaskB(), Times.Once);
}
}
I tried to set up a mock for the interface of my class under test, but the cls won't call it:
[TestMethod]
public void Test()
{
using (var mock = AutoMock.GetLoose())
{
mock.Mock<IClassA>().Setup(x => x.GetExternalData(It.IsAny<string>())).Return("MyData"); //<--- Mocking the method here is not detected by the cls below
mock.Mock<IClassB>().Setup(x => x.TaskB(It.IsAny<string>()));
var cls = mock.Create<ClassA>();
//act
cls.ConfigureExpansion();
mock.Mock<IClassB>().Verify(x => x.TaskB(), Times.Once);
}
}
I've also tried instantiating my class-under-test and when I do it like this, it doesn't take the mocks (ClassB) into consideration:
[TestMethod]
public void Test()
{
using (var mock = AutoMock.GetLoose())
{
mock.Mock<IClassA>().Setup(x => x.GetExternalData(It.IsAny<string>())).Return("MyData"); //<--- Mocking the method here is not detected by the cls below
mock.Mock<IClassB>().Setup(x => x.TaskB(It.IsAny<string>()));
var cls = new ClassA();
//act
cls.ConfigureExpansion();
mock.Mock<IClassB>().Verify(x => x.TaskB(), Times.Once);
}
}
I would really appreciate any insights about this,
Thank you
Here is one approach for your problem. If you want to test ConfigureExpansion of ClassA, you have to mock the dependencies used in that method, which is ClassB. You cannot mock GetExternalData of ClassA because ClassA is the class under test now. You may have to refactor your classes in a way so that there is a ClassUnderTest which creates both instances of ClassA and ClassB using dependency injection. Then, you can use Moq to mock the interfaces IClassA and IClassB to test the ConfigureExpansion.
public class ClassUnderTest
{
private readonly IClassA _classA;
private readonly IClassB _classB;
public ClassUnderTest(IClassA classA, IClassB classB)
{
this._classA = classA;
this._classB = classB;
}
public void ConfigureExpansion()
{
var data = this._classA.GetExternalData();
this._classB.TaskB(data);
}
}
public interface IClassA
{
string GetExternalData();
}
public class ClassA : IClassA
{
public string GetExternalData()
{
return "some data";
}
}
public interface IClassB
{
void TaskB(string myData);
}
public class ClassB : IClassB
{
public void TaskB(string myData)
{
//Does some work
}
}
The test method can be:
[TestMethod]
public void Test()
{
using (var mock = AutoMock.GetLoose())
{
var mockClassA = mock.Mock<IClassA>();
var mockClassB = mock.Mock<IClassB>();
mockClassA.Setup(x => x.GetExternalData()).Returns("MyData");
var cls = new ClassUnderTest(mockClassA.Object, mockClassB.Object);
//act
cls.ConfigureExpansion();
mockClassB.Verify(x => x.TaskB(It.IsAny<string>()), Times.Once);
}
}
When I execute my test case, it fails for path within my machine which doesn't exist and I am getting below error:
System.IO.DirectoryNotFoundException: Could not find a part of the
path 'C:\Data1'.
Do I need some kind of fake/mock here to pass the test case or do we have other way to do this?
Class
public class DemoCls
{
public void Execute()
{
string dataFolder = #"C:\\Data1";
foreach (string X in Directory.EnumerateFiles(dataFolder, "test" + "*.xml"))
{
}
}
}
Test Case
[TestClass()]
public class DemoClsTests
{
[TestMethod()]
public void ExecuteTest()
{
var X = new DemoCls();
X.Execute();
}
}
Class should be refactored to remove tight coupling to implementation concerns that make it difficult to test.
//...Creat an abstraction that provides the desired behavior as a contract
public interface IDirectoryService {
IEnumerable<string> EnumerateFiles(string path, string searchPattern);
}
A fake/mock can be created for when testing to avoid pitfalls associated with testing IO code in isolation.
A mocking framework could have been used for stubbing the dependencies, but for this example using a simple
public class FakeDIrectoryService : IDirectoryService {
IEnumerable<string> files;
public FakeDIrectoryService(IEnumerable<string> files) {
this.files = files;
}
public IEnumerable<string> EnumerateFiles(string path, string searchPattern = null) {
return files;
}
}
Class needs to be refactored now to follow Explicit Dependencies Principle via constructor and method injection.
public class DemoCls {
IDirectoryService directory;
public DemoCls(IDirectoryService directory) {
this.directory = directory;
}
public void Execute(string dataFolder) {
foreach (var x in directory.EnumerateFiles(dataFolder, "test*.xml")) {
//...
}
}
}
Test can now be properly exercised in isolation.
[TestClass()]
public class DemoClsTests {
[TestMethod()]
public void ExecuteTest() {
//Arrange
var fakePath = "C:/temp";
var fakeFiles = new[] {
#"C:\\temp\\testfakefilename1.txt",
#"C:\\temp\\testfakefilename2.txt",
#"C:\\temp\\testfakefilename3.txt"
};
var service = new FakeDIrectoryService(fakeFiles);
var sut = new DemoCls(service);
//Act
sut.Execute(fakePath);
//Assert
//perform your assertions
}
}
Finally for production code the real implementation of the file service can wrap any source, be it disk or remote service.
For example
public class FileService : IDirectoryService {
public IEnumerable<string> EnumerateFiles(string path, string searchPattern) {
return Directory.EnumerateFiles(path, searchPattern);
}
}
This is just an example of what can be done. There is a lot of room for improvement but this should get things started.
Hardcoded paths are not good to have and I would recommend two options since the class is not static.
1st
public class DemoCls
{
public void Execute(string targetPath)
{
foreach (string X in Directory.EnumerateFiles(targetPath, "test" + "*.xml"))
{
}
}
}
This keeps things more flexible and reusable
2nd
public class DemoCls
{
private string _targetPath;
public DemoCls(string targetPath){
_targetPath = targetPath;
}
public void Execute(string targetPath)
{
foreach (string X in Directory.EnumerateFiles(targetPath, "test" + "*.xml"))
{
}
}
}
This way keeps the Execute method cleaner (less preferred)
I'm new to Moq and I would like to mock certain part of my method to test the business logic but having problem to mock the GetCountry method. Below is the code that I used as sample.
public class Class1
{
public void Process()
{
MyClass foo = new MyClass();
var o = foo.GetCountry(); //I would like to mock this part.
//Business Logic here
}
}
public class MyClass : IFoo
{
public List<string> GetCountry()
{
//Get the data from Database.. someone will do this
throw new NotImplementedException();
}
}
Below is my Test Code that I used.
[TestMethod]
public void TestMethod2()
{
var mock = new Moq.Mock<IFoo>();
mock.Setup(m => m.GetCountry()).Returns(new List<string> { "America", "Philippines", "Japan" });
ClassLibrary1.Class1 foo = new ClassLibrary1.Class1();
//still called the not implemented exception
foo.Process();
}
Your code currently doesn't have an easy way to replace one implementation to another. Try this approach:
public class Class1
{
// Instead of using a concrete class, use an interface
// also, promote it to field
IFoo _foo;
// Create a constructor that accepts the interface
public Class1(IFoo foo)
{
_foo = foo;
}
// alternatively use constructor which provides a default implementation
public Class1() : this(new MyClass())
{
}
public void Process()
{
// Don't initialize foo variable here
var o = _foo.GetCountry();
//Business Logic here
}
}
If you have such setup it is quite easy to mock it using your code:
[TestMethod]
public void TestMethod2()
{
var mock = new Moq.Mock<IFoo>();
mock.Setup(m => m.GetCountry()).Returns(new List<string> { "America", "Philippines", "Japan" });
// Pass mocked object to your constructor:
ClassLibrary1.Class1 foo = new ClassLibrary1.Class1(mock.Object);
foo.Process();
}
Here is a very simplistic example of what I'm trying to do:
public class Bar
{
public void SomeMethod(string param)
{
//whatever
}
}
public interface IBarRepository
{
List<Bar> GetBarsFromStore();
}
public class FooService
{
private readonly IBarRepository _barRepository;
public FooService(IBarRepository barRepository)
{
_barRepository = barRepository;
}
public List<Bar> GetBars()
{
var bars = _barRepository.GetBarsFromStore();
foreach (var bar in bars)
{
bar.SomeMethod("someValue");
}
return bars;
}
}
In my test, I'm mocking IBarRepository to return a concrete List defined in the unit test and passing that mocked repository instance to the FooService constructor.
I want to verify in the FooService method GetBars that SomeMethod was called for each of the Bars returned from the repository. I'm using Moq. Is there any way to do this without mocking the list of Bars returned (if even possible) and not having to put some hacky flag in Bar (yuck) ?.
I'm following an example from a DDD book, but I'm starting to think it smells because I'm challenged in testing the implementation....
Revised... this passes:
public class Bar
{
public virtual void SomeMethod(string param)
{
//whatever
}
}
public interface IBarRepository
{
List<Bar> GetBarsFromStore();
}
public class FooService
{
private readonly IBarRepository _barRepository;
public FooService(IBarRepository barRepository)
{
_barRepository = barRepository;
}
public List<Bar> GetBars()
{
var bars = _barRepository.GetBarsFromStore();
foreach (var bar in bars)
{
bar.SomeMethod("someValue");
}
return bars;
}
}
[TestMethod]
public void Verify_All_Bars_Called()
{
var myBarStub = new Mock<Bar>();
var mySecondBarStub = new Mock<Bar>();
var myBarList = new List<Bar>() { myBarStub.Object, mySecondBarStub.Object };
var myStub = new Mock<IBarRepository>();
myStub.Setup(repos => repos.GetBarsFromStore()).Returns(myBarList);
var myService = new FooService(myStub.Object);
myService.GetBars();
myBarStub.Verify(bar => bar.SomeMethod(It.IsAny<string>()), Times.Once());
mySecondBarStub.Verify(bar => bar.SomeMethod(It.IsAny<string>()), Times.Once());
}
Note the slight change to class Bar (SomeMethod() is virtual). A change, but not one involving a flag... :)
Now, in terms of broader design, there is some mutation going on with your bar (whatever "SomeMethod()" actually does). The best thing to do would probably be to verify that this mutation happened on each Bar returned from FooService.GetBars(). That is, setup your repository stub to return some bars, and then verify that whatever mutation is performed by SomeMethod() has taken place. After all, you control the Bars that will be returned, so you can setup their pre-SomeMethod() state, and then inspect their post-SomeMethod() state.
If I was writing these classes with unit testing in mind, I would likely either have the class Bar implement an interface IBar and use that interface in my service, or make SomeMethod virtual in Bar.
Ideally like this:
public interface IBar
{
void SomeMethod(string param);
}
public class Bar : IBar
{
public void SomeMethod(string param) {}
}
public interface IBarRepository
{
List<IBar> GetBarsFromStore();
}
public class FooService
{
private readonly IBarRepository _barRepository;
public FooService(IBarRepository barRepository)
{
_barRepository = barRepository;
}
public List<IBar> GetBars()
{
var bars = _barRepository.GetBarsFromStore();
foreach (var bar in bars)
{
bar.SomeMethod("someValue");
}
return bars;
}
}
Then my unit test would look as follows:
[Test]
public void TestSomeMethodCalledForEachBar()
{
// Setup
var barMocks = new Mock<IBar>[] { new Mock<IBar>(), new Mock<IBar>() };
var barObjects = barMocks.Select(m => m.Object);
var repoList = new List<IBar>(barsObjects);
var repositoryMock = new Mock<IBarRepository>();
repositoryMock.Setup(r => r.GetBarsFromStore()).Returns(repoList);
// Execute
var service = new FooService(repositoryMock.Object);
service.GetBars();
// Assert
foreach(var barMock in barMocks)
barMock.Verify(b => b.SomeMethod("someValue"));
}