flq
flq

Reputation: 22849

How to reproducably cause / provoke a ReflectionTypeLoadException?

Sadly, references to this exception are usually of an exotic nature and can happen when you e.g. enumerate Types via Assembly.GetTypes() - case in point, it is happening on one of our deployments but the same set of assemblies work fine on the Integration Server.

In order to harden against this type of error I would like to be able to provoke such an exception to see if my exception handling code works as expected.

Hence any pointers would be useful, e.g. just knowing what kind of things cause this exception.

EDIT My attempt so far:

  • Define a type in assembly A which uses an attribute of assembly B
  • Have some code iterate over all types in the assembly where said attribute is specified.
  • I build the attribute only when DEBUG flag is true
  • I then copy the release build of that dependency into the relevant folder

But I only manage to get a TypeLoadException with a pretty clear error message

Upvotes: 4

Views: 430

Answers (2)

Tim Lloyd
Tim Lloyd

Reputation: 38444

Another approach if you wish to test how your code handles the exception is to use mocking in your testing. With mocking you can mock out the assembly loading sub-system and concentrate on testing how you handle the resulting exception - much more straight-forward.

Using mocking you would use an IAssemblyService instead of calling GetTypes on Assembly directly. In your mock you can throw the required exception. It is more usual to use a mocking framework such as FakeItEasy, but the following uses a hand-rolled mock for demonstration.

In your test you would substitute your real assembly service with MockAssemblyService.

internal class MyTypeThatLoadsStuff
{
    public MyTypeThatLoadsStuff(IAssemblyService assemblyService)
    {
        //Do stuff with assemblyService
    }
}

internal interface IAssemblyService
{
    IEnumerable<Type> GetTypes();
}

internal class AssemblyService : IAssemblyService
{
    private readonly Assembly _assembly;

    public AssemblyService(Assembly assembly)
    {
        _assembly = assembly;
    }

    public IEnumerable<Type> GetTypes()
    {
        return _assembly.GetTypes();
    }
}

internal class MockAssemblyService : IAssemblyService
{
    public IEnumerable<Type> GetTypes()
    {
        throw new ReflectionTypeLoadException();
    }
}

And with a mocking framework such as FakeItEasy:

[Test]
public void Test()
{
    IAssemblyService service = A.Fake<IAssemblyService>();

    ReflectionTypeLoadException ex = new ReflectionTypeLoadException(
        new[] { typeof(SprocketTests) }, new[] { new Exception() });

    A.CallTo(() => service.GetTypes()).Throws(ex);

    MyTypeThatLoadsStuff loader = new MyTypeThatLoadsStuff(service);

    //test...
}

Upvotes: 2

Daniel Hilgarth
Daniel Hilgarth

Reputation: 174329

The following causes this exception:

You have assembly A which defines the following class:

public class AC
{
    public BC GetBC() { /* ... */ }
}

You have assembly B which defines the class BC. Now, when you load Assembly A and get the members of class AC, for example using assembly.GetTypes().SelectMany(t => t.GetMembers()).ToList();, the framework tries to resolve BC. It even knows that it is in assembly B. However, if the framework resolves an assembly B that doesn't contain BC, a TypeLoadException will be thrown. This can happen, if assembly B is not up-to-date, because you forgot it in your deployment.

UPDATE:
To actually get a ReflectionTypeLoadException, the scenario is very similar. However, you don't need to have a method in AC that returns BC but you need to derive AC from BC:

public class AC : BC
{
}

Using the LoaderExceptions property, you can retrieve the exceptions that lead to this ReflectionTypeLoadException. In my case, this is a TypeLoadException stating exactly what type it couldn't load.

Upvotes: 4

Related Questions