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 in 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 in 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 effecting 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 those 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: that use of the word mock is inconsistent with any definition of the word.]
So, 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?
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 test 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 in my mind too, when I started to learn this stuff at first. They are very close in concept , but once you understand then properly then you will realize the actual difference. Yes, I have used the word “realize” purposefully. This is the matter of realization.
Still if you are confused by them then here is another shot for 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)
- {
-
- return false;
- }
- }
-
-
- public class StubExtensionManager : IExtensionNanager
- {
- public bool CheckExtension(string FileName)
- {
- return true;
- }
- }
-
- public class FileChecker
- {
- IExtensionNanager objmanager = null;
-
- public FileChecker()
- {
- objmanager = new ExtensionManager();
- }
-
- 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()
- {
-
- StubExtensionManager stub = new StubExtensionManager();
- FileChecker checker = new FileChecker(stub);
-
-
- bool IsTrueFile = checker.CheckFile("myFile.whatever");
-
-
- 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 to pass.
Implement Mock in Example
Fine, we will now implement a mock. As I said, there are many mocking frameworks in the market, though we will not 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 ate 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);
- }
-
- public class MockExtensionService : IServiceProvider
- {
- public string ErrorMessage = null;
- public void extensionService(string fileName)
- {
- if (fileName.Split('.')[1] != "myType")
- {
- ErrorMessage = "Wrong Type";
- }
- }
- }
-
-
- 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 of 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()
- {
-
- MockExtensionService mockobject = new MockExtensionService();
-
- ExtensionAnalyzer analyzer = new ExtensionAnalyzer(mockobject);
-
- analyzer.ExtensionCheck("somefile.someextension");
-
-
- 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.
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.