Kjell Rilbe
Kjell Rilbe

Reputation: 1509

How to mock a class to be found via reflection?

I have a method that finds a class using reflection, and I want to unit test it.

In assembly to be tested:

namespace MyApp.Workers
{
    internal interface IWork { void DoWork() }

    internal class RealWork : IWork { public void DoWork() { /* impl omitted */ } }
}

namespace MyApp.Helpers
{
    internal static class ClassFetcher
    {
        public static Type GetWorkClass(string className)
        {
            string qualifiedClassName = typeof(IWork).Namespace + "." + className;
            cls = Type.GetType(qualifiedClassName);
            if (cls == null)
                throw new Exception($"Can't find class \"{className}\".");
            if (!typeof(IWork).IsAssignableFrom(cls))
                throw new Exception($"The class \"{className}\" doesn't implement IWork.");
        }
    }
}

In test assembly:

// Usings omitted...

namespace MyApp.Workers
{
    // Class that does implement IWork.
    public class TestWork : IWork { public void DoWork() {} }

    // Class that does not implement IWork.
    public class TestNoWork { }
}

namespace MyApp_Test.Helpers
{
    [TestClass]
    public class UnitTestClassFetcher
    {
        [TestMethod]
        public void FindsWorkClass()
        {
            ClassFetcher.GetWorkClass("TestWork");
        }

        [TestMethod]
        public void DoesNotAcceptNoWorkClass()
        {
            ClassFetcher.GetWorkClass("TestNoWork");
        }
    }
}

On the GetWorkClass calls from the test assembly, the Type.GetType(...) call inside GetWorkClass returns null. If I pass "RealWork" from the test method it works.

So, how can I enable the Type.GetType(...) call inside the assembly to be tested to find the test classes that are declared inside the unit test assembly?

Suggestions both with and without third-party frameworks, tools, addons are welcome.

SOLUTION As per the comment from @LasseV.Karlsen and the marked answer from @dymanoid, I just changed the test method's code like this:

[TestMethod]
public void FindsWorkClass()
{
    string namespace = typeof(IWork).Namespace;
    string className = typeof(TestWork).AssemblyQualifiedName.Substring(namespace.Length + 1);
    ClassFetcher.GetWorkClass(className);
}

Upvotes: 1

Views: 844

Answers (1)

dymanoid
dymanoid

Reputation: 15227

You need to use the AssemblyQualifiedName, because your test type resides in a different assembly, not where the GetWorkClass method is defined. Without providing the full assembly qualified name, the Type.GetType method searches only in the executing assembly and in mscorlib.

Either change your method's implementation such that it uses assembly qualified names (e.g. by providing the assembly name as an optional parameter), or define the TestWork class in the same assembly where the GetWorkClass is defined (that's not a good suggestion, however).

Upvotes: 1

Related Questions