DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

How are you handling the data revolution? We want your take on what's real, what's hype, and what's next in the world of data engineering.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

SBOMs are essential to circumventing software supply chain attacks, and they provide visibility into various software components.

Related

  • The Anatomy of a Microservice, Satisfying the Interface
  • Mock the File System
  • How to Banish Anxiety, Lower MTTR, and Stay on Budget During Incident Response
  • Driving DevOps With Smart, Scalable Testing

Trending

  • Squid Game: The Clean Code Trials — A Java Developer's Survival Story
  • Docker Model Runner: Running AI Models Locally Made Simple
  • Microservice Madness: Debunking Myths and Exposing Pitfalls
  • Why Traditional CI/CD Falls Short for Cloud Infrastructure
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Testing, Tools, and Frameworks
  4. Mocking Internal Interfaces with Moq

Mocking Internal Interfaces with Moq

By 
Juri Strumpflohner user avatar
Juri Strumpflohner
·
Mar. 14, 13 · Interview
Likes (0)
Comment
Save
Tweet
Share
8.9K Views

Join the DZone community and get the full member experience.

Join For Free

When creating some Class Library you should pay attention to the visibility of its members and have a clear vision of what you’d like to expose to its users and what on the other side should be hidden. When writing unit tests against such assemblies however, you obviously want to test everything, from the internal members to the externally exposes parts.

Assume you have a class library named Base containing the following classes and interfaces

  • ICommandHandler - which is a publicly exposed interface
  • CommandHandler - basically its concrete implementation
  • IUndoRedoStack<T> - an interface that is used only internally
  • UndoRedoStack<T> - its concrete implementation

Note that I’m programming exclusively against interaces as that’s a major requirement for being able to create the necessary isolation for testing each component on its own.

Testing Classes with Internal Visibility

Lets take a closer look at the CommandHandler class

class CommandHandler : ICommandHandler
{
    //...
}

When creating a test for the CommandHandler class you would proceed as follows

[TestClass]
public class CommandHandlerTest
{
    
    private CommandHandler commandHandler;

    [TestInitialize]
    public void Setup()
    {
        commandHandler = new CommandHandler();
    }

    [TestCleanup]
    public void Teardown()
    {
        commandHandler = null;
    }


    [TestMethod]
    publiic void ShouldExecuteAGivenCommand()
    {
        //the test content
    }
}

When you execute such test, it won’t compile however. A best practice is to place the tests in a separate DLL (I usually name it like Base.UnitTests if the tested assembly is called Base) and as such, CommandHandler won’t be visible as it has been defined to only have internal visibility. In a previous blog post I already explained on how to overcome this issue, namely by specifying the InternalsVisibleTo attribute in the tested assembly. Check out that blog post for more details.

Mocking Interfaces with Internal Visibility using Moq

Now, CommandHandler has a dependency on IUndoRedoStack<T>

class CommandHandler : ICommandHandler
{
    public CommandHandler(IUndoRedoStack<ICommand> undoRedoStack) 
    {
        //...
    }
}

The CommandHandler has an Execute(command) method and suppose we’d like to test the fact that when calling it with a given ICommand object, that specific object gets added to the undoRedoStack. We would write

    [TestInitialize]
    public void Setup()
    {
        mockUndoRedo = new Mock<IUndoRedoStack<ICommand<<();
        handler = new CommandHandler(mockUndoRedo.Object);
    }

    [TestMethod]
    public void ShouldAddTheCommandToTheUndoStack()
    {
        //arrange
        var myCommand = new MyTestCommand();

        //act
        handler.Execute(myCommand);

        //assert
        mockUndoRedo.Verify(x =< x.AddItem(myCommand), Times.Once(), "The command should have been added to the undo stack");
    }

When executing the test, it fails with

Message: Initialization method Base.UnitTests.Command.CommandHandlerTest thre exception.
Castle.DynamicProxy.Generators.GeneratorException:
Castle.DynamicProxy.Generators.GeneratorException: Type Base.Command.IUndoRedoStackBase.Command.ICommand, Base, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null is not public. Can not create proxy for types that are not accessible.

The problem is the same, the Moq library I use for stubbing here, has no visibility on the internal member types and as such we need to add another InternalsVisibleTo attribute specifically for Moq. The most intuitive thing to do would be

[assembly: InternalsVisibleTo("Moq")]

but unfortunately that doesn’t work. Instead you need to add

[assembly:InternalsVisibleTo("DynamicProxyGenAssembly2")]

which is used internally by Moq to generate proxy classes. Note, as already described by this blog post this only works if your assembly is not strongly-named, otherwise you have to include the assembly’s PublicKey as well.

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=...")]

Interface (computing) unit test

Published at DZone with permission of Juri Strumpflohner. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • The Anatomy of a Microservice, Satisfying the Interface
  • Mock the File System
  • How to Banish Anxiety, Lower MTTR, and Stay on Budget During Incident Response
  • Driving DevOps With Smart, Scalable Testing

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • [email protected]

Let's be friends: