This is a migrated thread and some comments may be shown as answers.

Mocking contructors (future mocking?)

3 Answers 32 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Nacho
Top achievements
Rank 1
Nacho asked on 13 Feb 2014, 02:19 PM
Hello, 

I'm trying to test the following code:

public ICollection<RawCatalog> ReadCatalog(string familyName)
{
    // Root folder for the family
    string familyFolder = this.GetFamilyFolder(familyName);
    DirectoryInfo familyFolderInfo = new DirectoryInfo(familyFolder);
 
    foreach (DirectoryInfo subFamilyFolderInfo in familyFolderInfo.EnumerateDirectories())
    {
        // Do stuff
    }
}

I expected that this would work:

// Arrange
DirectoryInfo fakeDirectoryInfo = Mock.Create<DirectoryInfo>(Constructor.Mocked);
Mock.Arrange(() => new DirectoryInfo(@"testRoot\DrivesData\TestFamily")).Returns(fakeDirectoryInfo);
Mock.Arrange(() => directoryInfo.EnumerateDirectories()).Returns(new DirectoryInfo[] { });

But is not working as seems that fakeDirectoryInfo is not being returned in the constructor. How should I do the test? (I should not change the source code as it's working code if possible).

I've read something about future mocking and using DoNothing() but not sure if this apply to my own situation.

Thanks in advance.

3 Answers, 1 is accepted

Sort by
0
Kaloyan
Telerik team
answered on 17 Feb 2014, 11:56 AM
Hello Nacho,

Thank you for contacting our support system.

Unfortunately, arranging a return value on a constructor interception is not possible with JustMock.
(Mock.Arrange(() => new DirectoryInfo(@"testRoot\DrivesData\TestFamily")).Returns(fakeDirectoryInfo);)

I managed to prepare an example for you, that tests very similar scenario. First, let's assume we have the following system under test:
public class TestClass
{
    public string GetFamilyFolder(string familyName)
    {
        return @"testRoot\DrivesData\TestFamily";
    }
 
    public ICollection<DirectoryInfo> ReadCatalog(string familyName)
    {
        // Root folder for the family
        string familyFolder = this.GetFamilyFolder(familyName);
        DirectoryInfo familyFolderInfo = new DirectoryInfo(familyFolder);
 
        var collection = new List<DirectoryInfo>();
        foreach (DirectoryInfo subFamilyFolderInfo in familyFolderInfo.EnumerateDirectories())
        {
            collection.Add(subFamilyFolderInfo);
        }
 
        return (ICollection<DirectoryInfo>)collection;
    }
}

Now, to test the ReadCatalog function, we will need to isolate the DirectoryInfo calls. Here is the test method:
[TestMethod]
public void TestMethod1()
{
    // Arrange
    // Defining some parameters for the test.
    var expected = new DirectoryInfo("test");
    var passedString = @"testRoot\DrivesData\TestFamily";
 
    // Instantiating our class under test.
    var sUT = new TestClass();
 
    // This will arrange the constructor of any new DirectoryInfo instance,
    //  that matches the passedString argument, to do nothing.
    Mock.Arrange(() => new DirectoryInfo(passedString)).DoNothing();
 
    // Dummy instance, needed for the future arrange on the next line.
    var directoryInfo = new DirectoryInfo("test");
 
    // Arranging directoryInfo.EnumerateDirectories() to return a fake collection
    //  no matter the instance that is called from. This is also called Future Mocking.
    Mock.Arrange(() => directoryInfo.EnumerateDirectories())
        .IgnoreInstance()
        .Returns(new DirectoryInfo[] { expected });
 
    // Act
    var actual = sUT.ReadCatalog(passedString);
 
    // Assert
    Assert.AreEqual(1, actual.Count);
    Assert.AreEqual(expected.Name, actual.FirstOrDefault().Name);
}
In the above, I have used Future Mocking along with its feature - Future Constructor Mocking.

I hope this gives a starting point for your test scenario. Please, do not hesitate to contact us again if there is anything else, we can help you with.

Regards,
Kaloyan
Telerik
Share what you think about JustTrace & JustMock with us, so we can become even better! You can use the built-in feedback tool inside JustTrace, our forums, or our JustTrace or JustMock portals.
0
Nacho
Top achievements
Rank 1
answered on 17 Feb 2014, 01:28 PM
Thanks for your reply Kaloyan.

With the proposed solution how do differentiate different instances? Modifying your method slightly so it resembles the real one:

public ICollection<DirectoryInfo> ReadCatalog(string familyName)
{
    // Root folder for the family
    string familyFolder = this.GetFamilyFolder(familyName);
    DirectoryInfo familyFolderInfo = new DirectoryInfo(familyFolder);
 
    var collection = new List<DirectoryInfo>();
    foreach (DirectoryInfo subFamilyFolderInfo in familyFolderInfo.EnumerateDirectories())
    {
        subFamilyFolderInfo.EnumerateDirectories();
        foreach (DirectoryInfo childFamilyFolderInfo in familyFolderInfo.EnumerateDirectories())
        {
            collection.Add(childFamilyFolderInfo);
        }
    }
 
    return (ICollection<DirectoryInfo>)collection;
}

How could I test the two loops if I can only set one expectation?

On the other hand just a proposal, if a method call makes no sense (like adding a return to a constructor arrange) could be possible to throw an exception to be aware that this is an invalid construct.

Thanks again for your help!
0
Accepted
Kaloyan
Telerik team
answered on 19 Feb 2014, 02:57 PM
Hi again Nacho,

This is interesting scenario for which you can use the JustMocks Sequential Mocking feature. You can try the following test:
[TestMethod]
public void TestMethod1()
{
    // Arrange
    // Defining some parameters for the test.
    var expected1 = new DirectoryInfo("test1");
    var expected2 = new DirectoryInfo("test2");
    var passedString = @"testRoot\DrivesData\TestFamily";
 
    // Instantiating our class under test.
    var sUT = new TestClass();
 
    // This will arrange the constructor of any new DirectoryInfo instance,
    //  that matches the passedString argument, to do nothing.
    Mock.Arrange(() => new DirectoryInfo(passedString)).DoNothing();
 
    // Dummy instance, needed for the future arrange on the next line.
    var directoryInfo = new DirectoryInfo("test");
 
    // Arranging directoryInfo.EnumerateDirectories() to return a fake collection
    //  no matter the instance that is called from. This is also called Future Mocking.
    //  Additionally I have applied sequential mocking in order to arrange to correct return
    //  value for the specific call iteration.
    Mock.Arrange(() => directoryInfo.EnumerateDirectories())
        .IgnoreInstance()
        .Returns(new DirectoryInfo[] { expected1 }).InSequence();
 
    Mock.Arrange(() => directoryInfo.EnumerateDirectories())
        .IgnoreInstance()
        .Returns(new DirectoryInfo[] { expected2 }).InSequence();
 
    // Act
    var actual = sUT.ReadCatalog(passedString);
 
    // Assert
    Assert.AreEqual(1, actual.Count);
    Assert.AreEqual(expected2.Name, actual.FirstOrDefault().Name);
}

About your proposal, I must say it is a thing we defenetely must consider for our future releases. So, thank you for the idea!

Regards,
Kaloyan
Telerik
Share what you think about JustTrace & JustMock with us, so we can become even better! You can use the built-in feedback tool inside JustTrace, our forums, or our JustTrace or JustMock portals.
Tags
General Discussions
Asked by
Nacho
Top achievements
Rank 1
Answers by
Kaloyan
Telerik team
Nacho
Top achievements
Rank 1
Share this question
or