Search code examples
c#moqxunit

KeyNotFoundException when trying to access mocked object in dictionary


My mock test is throwing a KeyNotFoundException:

[Fact]
public void MockAssembly_GetTypes_ReturnsMockedTypes()
{
    var mockAssembly = new Mock<Assembly>();

    mockAssembly.Setup(a => a.GetTypes()).Returns(new Type[] { typeof(MyClass) });
    var mockAssemblyObject = mockAssembly.Object;

    var assemblyDictionary = new Dictionary<Assembly, HashSet<Type>>();
    if (!assemblyDictionary.TryGetValue(mockAssemblyObject, out var types))
    {
        types = new HashSet<Type>(mockAssemblyObject.GetTypes());
        assemblyDictionary[mockAssemblyObject] = types;
    }

    Assert.Contains(mockAssemblyObject, assemblyDictionary.Keys);
    Assert.Single(assemblyDictionary[mockAssemblyObject]);
}

System.Collections.Generic.KeyNotFoundException: The given key '' was not present in the dictionary.

On the line Assert.Single(assemblyDictionary[mockAssemblyObject]);

Even mocking GetHashCode doesn't help - it still tries to use an empty key.

Why is this happening?

Edit:

Further testing shows if I call assemblyDictionary.TryGetValue(mockAssemblyObject, out var myTypes); even immediately after I add using assemblyDictionary.Add(mockAssemblyObject, types) the result is false and null.


Solution

  • Set CallBase to true:

    var mockAssembly = new Mock<Assembly>() { CallBase = true };
    

    Both Equals and GetHashCode are also virtual methods, and unless you set CallBase to true, Moq will also override these methods with 'mock' implementations.

    It's not quite obvious that this fixes the problem, but in my repro of the OP, it does. The test now passes.