Understand Stub, Mock and Fake in Unit Testing

Welcome to the Unit Testing article series, in this series we are talking about unit testing, various concepts, and ideas of unit testing with examples. If you are new to the world of unit testing, please feel free to go through previous articles.

This article explains three very important concepts called Stub, Mock, and Fake in terms of unit testing and will see how they are used depending on the scenario. Those are a bit of a conceptual idea of unit testing, if you are very new to unit testing and de-coupled architecture then I suggest you understand the concept of unit testing at first.

Let's understand them theoretically then we will implement each one practically. All three are tightly related to unit testing and de-coupled architecture.

We know that de-coupling is the primary purpose of software design so that we can detach one without affecting the other or with minimal impact.

Another big advantage of de-coupled is unit testing. For example, I have a class to be unit tested and the class depends on some other external dependency like DB operation or service call. Now, I want to test the class where the dependent objects are not ready yet, so in this situation, I need to implement a Mock or Fake object to test my class. We will skip the actual DB operation or service call using them. In this way, we can check our business logic.

Fine, so we understand what the basic uses of that stuff are. Now, let's understand the formal definition.

What is Mock?

A mock object is a fake object in the system that decides whether the unit test has passed or failed. If does so by verifying whether the object under test interacted as expected with the fake object. There's usually no more than one mock per test.

Editor's note. the use of the word mock is inconsistent with any definition of the word.

Test

So, a mock is nothing but an object that mimics an actual object. There are various ways to implement a mock object and various frameworks available in the market to implement mocking. Oh, I forgot to talk about the image, Yes we know of a mock test in our school days, you may even have tried in your home too, to get a good mark in an exam.

What is Stub?

Stub

A stub can replace an object in the unit testing world. For example, I have implemented one function to send mail that is half functional or not yet functional. So, I can implement one stub to reflect the non-functional mail-sending function. And if it needs to return “true” always to continue unit testing the application, I can implement a stub to reflect the mail-sending functionality that will return true always.

Oh, they both seem confusing!

Yes, this thought came into my mind too, when I started to learn this stuff at first. They are very close in concept, but once you understand them properly then you will realize the actual difference. Yes, I have used the word “realize” purposefully. This is a matter of realization.

Still, if you are confused by them then here is another shot for clarification.

Clarification

Yes, a stub cannot fail your unit test because you know what you are implementing and why you are implementing it. But a mock is just an object that mimics the real object. If our business logic in code is wrong then the unit test will fail even if we pass a correct mock object.

Now, I think you are very nearly clear about stub and mock. Let's understand fake now.

What is Fake?

As we know, the dictionary meaning of fake is, not real. Yes, it's the same in terms of unit testing. It's a general meaning, it might point to a stub or a mock or dummy or something that is not real.

So, fake is a generic term, that can point to anything.

Let's implement a stub in action

As we are a .NET developer, we will use C# as the programming language, but the concept is the same for all programming languages.

Have a look at the following example.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ConsoleApp.Company;

namespace ConsoleApp
{
    public interface IExtensionNanager
    {
        Boolean CheckExtension(string FileName);
    }

    public class ExtensionManager : IExtensionNanager
    {
        public bool CheckExtension(string FileName)
        {
            // Some complex business logic might go here. May be DB operation or file system handling
            return false;
        }
    }

    // Stub implementation to bypass actual Extension manager class.
    public class StubExtensionManager : IExtensionNanager
    {
        public bool CheckExtension(string FileName)
        {
            return true;
        }
    }

    public class FileChecker
    {
        IExtensionNanager objmanager = null;
        
        // Default constructor
        public FileChecker()
        {
            objmanager = new ExtensionManager();
        }

        // Parameterized constructor
        public FileChecker(IExtensionNanager tmpManager)
        {
            objmanager = tmpManager;
        }

        public Boolean CheckFile(String FileName)
        {
            return objmanager.CheckExtension(FileName);
        }
    }
}

The code is very simple to understand. We have implemented a simple FileChecker operation. The actual FileExtension manager class is not implemented fully and so we have implemented a stub version of the class. We are seeing that the CheckExtension function will always return true, as we defined explicitly.

Here is our code for the unit test.

using System;
using System.Web.Mvc;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MVCApplication.Controllers;
using Moq;
using ConsoleApp.Company;
using ConsoleApp;

namespace TestMVC
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            // Act
            StubExtensionManager stub = new StubExtensionManager();
            FileChecker checker = new FileChecker(stub);

            // Action
            bool IsTrueFile = checker.CheckFile("myFile.whatever");

            // Assert
            Assert.AreEqual(true, IsTrueFile);
        }
    }
}

And the test will always pass because we have used the function that is defined within the stub class and it will make the unit test true always.

Ok, so once again to clarify the fundamental idea, a stub is used to always pass the unit test because we know what we are implementing and why. Our intention is to get the unit test.

Implement Mock in Example

Fine, we will now implement a mock. As I said, there are many mocking frameworks in the market, and though we will use none of them, we will implement a simple handwritten mocking.

Another key point about mock is, we can use a mock object to check unit testing. I mean within assert, but we cannot with stub. Have a look at the following code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ConsoleApp.Company;

namespace ConsoleApp
{
    public interface IServiceProvider
    {
        void extensionService(string fileName);
    }

    // Mock extenison service provider
    public class MockExtensionService : IServiceProvider
    {
        public string ErrorMessage = null;
        public void extensionService(string fileName)
        {
            if (fileName.Split('.')[1] != "myType")
            {
                ErrorMessage = "Wrong Type";
            }
        }
    }

    // Actual incomplete ExtensionManager functionality
    public class ExtensionManager : IServiceProvider
    {
        public void extensionService(string fileName)
        {
            throw new NotImplementedException();
        }
    }

    public class ExtensionAnalyzer
    {
        public IServiceProvider provider = null;
        public ExtensionAnalyzer(IServiceProvider tmpProvider)
        {
            provider = tmpProvider;
        }

        public void ExtensionCheck(string fileName)
        {
            provider.extensionService(fileName);
        }
    }
}

The implementation is very simple, we have just implemented a Mock class that will mimic the actual functionality. Here is the unit test for this code.

using System;
using System.Web.Mvc;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MVCApplication.Controllers;
using Moq;
using ConsoleApp.Company;
using ConsoleApp;

namespace TestMVC
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            // Act
            MockExtensionService mockobject = new MockExtensionService();
            // Inject mock object now
            ExtensionAnalyzer analyzer = new ExtensionAnalyzer(mockobject);
            // Action
            analyzer.ExtensionCheck("somefile.someextension");

            // Assert
            Assert.AreEqual(mockobject.ErrorMessage, "Wrong Type");
        }
    }
}

And we are seeing that the test has passed because the file extension is different than the expected one.

File extension

Conclusion

In this article, we have learned the concept of Stub and Mock in terms of unit testing. I hope this article helps you to understand them better. We need to pick the right one depending on the situation. A stub will help you when you want to replace the actual functionality, mock will help when you want to mimic the actual data.


Similar Articles