简体   繁体   中英

How can I mock the Parent accessor of a faked TreeNode in a unit test?

Using Kentico 12 SP, hotfix 64 - I can create faked TreeNode types and set values on most of the fields, but I can't set a return value for Parent which I need to do to run a test on a method.

The method I'm trying to test:

public Dictionary<string, string> GenerateBreadcrumbs(TreeNode treeNode)
{
    var breadcrumbs = new Dictionary<string, string>();
    if (treeNode != null) {
        var revBreadcrumbs = new Dictionary<string, string>();
        var thisNode = (treeNode.Parent != null && treeNode.Parent.NodeAliasPath != "/") ? treeNode.Parent : null;
        while (thisNode != null) {
            revBreadcrumbs.Add(thisNode.DocumentName, thisNode.NodeAliasPath.ToLowerInvariant());
            thisNode = (thisNode.Parent != null && thisNode.Parent.NodeAliasPath != "/") ? thisNode.Parent : null;
        }
        foreach (var item in revBreadcrumbs.Reverse())
        {
            breadcrumbs.Add(item.Key, item.Value);
        }
    }
    return breadcrumbs;
}

In the unit test I can Fake a document type of type Folder

DocumentGenerator.RegisterDocumentType<Folder>(Folder.CLASS_NAME);
Fake().DocumentType<Folder>(Folder.CLASS_NAME);

I can create instances and set values on other properties and they work as expected

Folder baseFolder = TreeNode.New<Folder>()
    .With(f => f.SetValue("DocumentName", docName))
    .With(f => f.SetValue("NodeAliasPath", docPath));

But when I try to set the return value for "Parent" it ignores that value when called by the method being tested.

Folder underFolder= TreeNode.New<Folder>()
    .With(f => f.SetValue("Parent", baseFolder));

I've tried using NSubstitute to change the return value of Parent underFolder.Parent.Returns(baseFolder); but it throws an exception "NSubstitute.Exceptions.CouldNotSetReturnDueToNoLastCallException : Could not find a call to return from." .

Searches on this error seem to indicate that I did not fake the class in the manner NSubstitute expected, which would be something like this: var mockFolder = Substitute.For<Folder>(); I tried the Moq version too, both returned the error System.TypeLoadException : Method 'DeleteInternal' on type 'Castle.Proxies.FolderProxy' from assembly 'DynamicProxyGenAssembly2... indicating that one or more properties of TreeNode can't be read by the mocking frameworks... ugh.

Anyway, should I be using a different strategy for testing this? I didn't want to have to write a wrapper for TreeNode but seems like I may have to to get this tested?

I don't think this is going to be possible with a Unit Test.

TreeNode.Parent is not a field/primitive value that is backed by a database field (even though NodeParentID is), so using .SetValue() is not going to have any effect.

In the source code, the TreeNode.Parent property makes at least 1 database query (potentially 2), and neither of these is handled by the Kentico Unit Test infrastructure.

My recommendation would be to use 1 of 2 options.

  1. Isolate your use of TreeNode.Parent by using an abstraction to get its value from a TreeNode , and then create a stub in your test using something like NSubstitute (or manually).
public interface ITreeNodeAccessor
{
    TreeNode GetParent(TreeNode node);
}
  1. Switch to an Integration Test .

I've personally taken both approaches when the Unit Test infrastructure fails to handle my use case - the one I take depends on what it is I'm actually trying to test.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM