I'm trying to create my own Mock function. I know Moq exists, but I really want to accomplish this.
I have no idea how I'd create a Mock function to stub out User#Foobar's calls to Product#Price in order to unit test User#Foobar:
using System;
public class MyUnitTest
{
// CODE BEING TESTED
class Product {
public string Price() {
return "I WANT TO STUB THIS OUT, DONT WANT TO SEE THIS STRING";
}
}
class User {
public string Foobar() {
Product product = new Product();
return $"Foobar, Product#price returns: {product.Price()}";
}
}
//////////////////////
// CODE THAT DOES THE TEST
public void Mock(string mockedClass, string mockedFunction, string mockedReturn)
{
// no idea what to put here something to do with an interface
}
public void RunTests()
{
Mock("Product","Price","MOCKED DATA");
string expected = new User().Foobar();
Assert(expected, "Foobar, Product#price returns: MOCKED DATA");
}
public void Assert(string actual, string expected){
Console.WriteLine(actual == expected);
}
//////////////////////
// How do I stub out Product to return "MOCKED DATA"?
}
public class Program
{
public static void Main(){
new MyUnitTest().RunTests();
}
}
I know how to do it in Ruby, but not in C#.
Here's a NET fiddle of the problem:
https://dotnetfiddle.net/8Re2jb
What should this Mock function do to intercept User#Foobar's call to Product#Price and return the string "MOCKED DATA"?
public void Mock(string mockedClass, string mockedFunction, string mockedReturn)
{
}
CodePudding user response:
You should approach this by using dependency injection. The User
object shouldn't know the concrete type of the Product
. Instead, you should encapsulate Product
behind an IProduct
interface and pass to the User
constructor either an IProduct
or some kind of IProduct
factory.
For example:
public interface IProduct
{
public string Price();
}
public interface IUser
{
public string FooBar();
}
public class User: IUser
{
public User(Func<IProduct> productFactory)
{
_productFactory = productFactory;
}
public string FooBar()
{
var product = _productFactory();
return $"Foobar, Product#price returns: {product.Price()}";
}
readonly Func<IProduct> _productFactory;
}
Then you can create your own "mock" product (which we should really call a stub):
public class MockProduct : IProduct
{
public MockProduct(string mockPrice)
{
_mockPrice = mockPrice;
}
public string Price()
{
return _mockPrice;
}
readonly string _mockPrice;
}
Then in your test you can create the User
and pass to it a factory method to create a mock IProduct
:
Func<IProduct> mockProductFactory = () => new MockProduct("MOCKED DATA");
User user = new User(mockProductFactory);
// Test user now.
Although this is really a form of stubbing (a term you already used) rather than mocking - mocking is generally done with a mocking framework and uses reflection to avoid having to manually implement all the methods in an interface.