Microsoft has mocking functionality called Fakes (which replaces the entire class) and Shims (which replaces selected methods). It is only available in the Enterprise version of Visual Studio. It's available in .Net Framework 4.0 and later and also in .Net Core with Visual Studio 2019 version 16.7 and later.
https://developercommunity.visualstudio.com/content/problem/956128/support-microsoft-fakes-on-net-core.html
Fire up your Enterprise Visual Studio 2019 and start a C#, .Net Framework, console project called StockPriceConsole.
The first thing to do is add a Class Library project called StockPrice. This is the class we will be testing. We start by adding an interface file to the StockPrice project (this is a common technique when mocking) called IStockPrice. It defines two methods and looks like this.
using System;
namespace StockPrice
{
public interface IStockPrice
{
Boolean IsSymbolValid(String Symbol);
Decimal GetStockPrice(String Symbol);
}
}
using System;
namespace StockPrice
{
public class StockPrice : IStockPrice
{
public decimal
GetStockPrice(string Symbol)
{
Random random = new Random();
if (IsSymbolValid(Symbol))
return (Decimal)Math.Round(random.NextDouble() * 100, 2);
else
throw new
ArgumentException("Invalid Symbol");
}
public bool
IsSymbolValid(string Symbol)
{
return (Symbol.Length == 4);
}
}
}
using System;
namespace StockPrice
{
class Program
{
static void Main(string[] args)
{
StockPrice stockPrice = new StockPrice();
String symbol = "CNET";
Console.WriteLine(string.Format("Stock price for {0} is {1}", symbol, stockPrice.GetStockPrice(symbol)));
Console.ReadLine();
}
}
}
You will now have a new folder called Fakes containing an XML file called StockPrice.fakes and a new reference called StockPrice.Fakes
If you open the StockPrice.fakes file you will see there's not much to it. If you have problems generating the fakes or shims you can add a Diagnostic attribute to generate useful error messages during the build.
<Fakes xmlns="http://schemas.microsoft.com/fakes/2011/" Diagnostic="true">
<Assembly Name="StockPrice"/>
</Fakes>You can tell if the fakes and shims were correctly generated by double-clicking on the StockPrice.Fakes reference and then expanding it. You should see something like this. If the StockPrice.Fakes node has no children, try the Diagnostics trick explained above, rebuild, and look in the Output window.
using System;
using
Microsoft.QualityTools.Testing.Fakes;
using
Microsoft.VisualStudio.TestTools.UnitTesting;
using
StockPrice;
namespace StockPriceTest
{
[TestClass]
public class GetStockPriceTest
{
[TestMethod]
public void
CheckIBMStockPriceWithFake()
{
// Uses fakes
to replace the entire StockPrice class
IStockPrice stockPrice = new StockPrice.Fakes.StubIStockPrice()
{
IsSymbolValidString = (symbol)
=> { return true; },
GetStockPriceString = (symbol)
=> { return 100; }
};
Decimal IBMStockPrice =
stockPrice.GetStockPrice("IBM");
Assert.AreEqual(100, IBMStockPrice, "IBM stock price should be 100");
}
}
}
As I said, when you Fake a class, any methods you don't override do nothing. Shims allow you to override some methods but leave others intact. Add another test method to StockPriceTest.cs like this. Note all Shimming must take place within a ShimsContext.
[TestMethod]
public void
CheckIBMStockPriceWithShim()
{
// Uses a shim
to replace the IsSymbolValid method only
using (ShimsContext.Create())
{
StockPrice.Fakes.ShimStockPrice.AllInstances.IsSymbolValidString =
(methodName, symbol) => { return true; };
IStockPrice stockPrice
= new StockPrice.StockPrice();
Decimal IBMStockPrice =
stockPrice.GetStockPrice("IBM");
Assert.IsTrue((IBMStockPrice
< 100), "Invalid stock price");
}
}
This test replaces IsSymbolValid so that all symbols are valid, but leaves GetStockPrice intact. This is very useful when you are testing a method that calls another method in the same class. You can Shim the second method but still test the first one.
Your test results should look like this.