4

I need xUnit to work with internal test classes. The problem is that I have used a generic base test fixture UnitTestBase. So I create my fixture as

class MyFixture: UnitTestBase<SomeSystemUnderTheTest>
{
...
}

In some cases SomeSystemUnderTheTest appears to be internal class. Lets call it SomeSystemUnderTheTestInternal. As result UnitTestBase<SomeSystemUnderTheTestInternal> also appear to be internal even if UnitTestBase public. As result of that I can't specify MyFixture to be public as compiler says your base class has less accessibility. So MyFixture in my case only can be internal, but then xUnit requires it to be public. Is there a workaround to make xUnit work with internal fixtures?

SomeSystemUnderTheTest is a class which implements some interface. It is not used directly anywhere it is just got injected by DI container. It was marked as internal. I have slightly simplified our situation above, SomeSystemUnderTheTest is in fact derived from a generic class SomeSystemUnderTheTestBase, where SomeInternalClass is an internal class and as result of this the whole tree is internal. I can't change it as it is not something we wanna do.

3
  • What is SomeSystemUnderTheTest ? Why is appears to be internal class in some cases? Does it appear a public class in other cases? How? Commented Jan 15, 2021 at 5:03
  • @ChetanRanpariya I have updated the question and explained what is the class and why it is internal Commented Jan 15, 2021 at 6:01
  • 1
    You don't really need that last paragraph explaining why a class may be internal. It's perfectly reasonable for a class to be internal! I'd just say "In some cases SomeSystemUnderTheTest will be an internal class" instead of "appears to be". Commented Jan 28, 2022 at 14:09

2 Answers 2

2

Add this just above the namespace declaration in your SomeSystemUnderTestInternal file:

[assembly: InternalsVisibleToAttribute("TestProject")]

Where TestProject is the assembly name of the project that contains your test class.

Sign up to request clarification or add additional context in comments.

3 Comments

I have this already it and it doesn't help. It might help if same attribute will be added to xUnit assemblies but I really doubt. xUnit explicitly says the test class should be public.
This just allows your test project to see your main project's internals. What the OP (and I) need would be an equivalent to put in the test project that allows the test project's internals to be visible to xUnit. You can do something similar for Moq (make main project's internals visible to Moq) - put <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo"> <_Parameter1>DynamicProxyGenAssembly2</_Parameter1> </AssemblyAttribute> in csproj, but it doesn't appear to be possible for Xunit. Maybe it would be too complicated for test classes, I don't know.
@jsabrooke: Actually, it is not xUnit that needs to "see" the test project's internals. It is plainly the C# compiler that will not allow declaring a class as public when its base class - or a generic parameter of its base class - has a lesser visibility.
1

Late answer, but just had to figure this out for myself. Here is one potential workaround pattern, coded in .NET 8:

Create a TestBase class

Define any test methods here

public abstract class TestBase
{
    [Fact]
    public abstract void TestMethod();
}

Modify UnitTestBase

Inherit from TestBase so this can be used as a delegate

public abstract class UnitTestBase<TSubjectUnderTest> : TestBase
{
    [Fact]
    public override void TestMethod()
    {
        // Implement test for TSubjectUnderTest
    }
}

Create a DelegateTestBase base class

Implement the test methods and delegate them. This is where the work-around actually happens

public abstract class DelegateTestBase : TestBase
{
    protected abstract TestBase GetDelegate();

    [Fact]
    public override void TestMethod
        => GetDelegate().TestMethod();
}

Modify MyFixture

Implement delegate pattern here

public class MyFixture : DelegateTestBase
{
    private class Delegate : UnitTestBase<SomeSystemUnderTheTest>;

    protected override TestBase GetDelegate() => new Delegate();
}

This works because MyFixture is public and can be discovered by xUnit. It allows the generic type class for the internal SomeSystemUnderTheTest to be provided by the delegate.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.