Search code examples
c#unit-testingenums

Using Extension Method on an Enum Type Leads to Compile Error (Extension Method Inaccessible)


I'm writing unit tests for a extension methods defined for an enum type. This is a test

namespace ABC.ACSUnitySDKTest
{
    [TestFixture]
    public class AudioStreamSampleRateExTests
    {
        [Test]
        public void ToHz_16000Hz_ReturnsCorrectValue()
        {
            var result = AudioStreamSampleRate.Hz_16000.ToHz(); // <-- ERROR! .ToHz() is not defined!
            Assert.That(result, Is.EqualTo(16000));
        }
    }
}

The full error message is:

CS1061 'AudioStreamSampleRate' does not contain a definition for 'ToHz' and no accessible extension method 'ToHz' accepting a first argument of type 'AudioStreamSampleRate' could be found (are you missing a using directive or an assembly reference?)

But the extension method is defined and C# compile should already see that:

namespace ABC
{
    internal static class AudioStreamSampleRateEx
    {
        public static int ToHz(this AudioStreamSampleRate sampleRate)
        {
            return sampleRate switch
            {
                AudioStreamSampleRate.Hz_16000 => 16000,
                AudioStreamSampleRate.Hz_22050 => 22050,
                AudioStreamSampleRate.Hz_24000 => 24000,
                AudioStreamSampleRate.Hz_32000 => 32000,
                AudioStreamSampleRate.Hz_44100 => 44100,
                AudioStreamSampleRate.Hz_48000 => 48000,
                _ => throw new NotImplementedException()
            };
        }
    }
}

So why can't C# compiler see the extension method .ToHz()?

Note: We don't need to add a 'using' statement because both of them are in the same namespace. Anyway, I added 'using' statement and it didn't solve the problem.


Solution

  • I realized why C# compiler cannot see the extension method. The access modifier internal on the extension method class AudioStreamSampleRateEx prevents this class and consequently the extension method to be accessible in the test class AudioStreamSampleRateExTests.

    In order to fix it, I added this attribute:

    [assembly: InternalsVisibleTo("ACSUnitySDKTest")]
    

    to the top of the file in which the 'internal' class was defined. This attribute makes the internal types and members of the assembly in which this attribute is declared are visible to another assembly, in this case "ACSUnitySDKTest" assembly.

    Problem solved!

    Update: Others mentioned I can replace the 'internal' access modifier with 'public'. Yes, it can solve the problem but the use of 'internal' is a design decision made by others and I'm not supposed to modify it.