繁体   English   中英

如何在 C# 单元测试中手动存根 function

[英]How to manually stub out a function in C# unit testing

我正在尝试创建自己的 Mock function。我知道 Moq 存在,但我真的很想完成这个。

我不知道如何创建 Mock function 来阻止 User#Foobar 对 Product#Price 的调用,以便对 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();
    }
}

Ruby知道怎么做,C#不知道。

这是问题的 .NET 小提琴:

https://do.netfiddle.net/8Re2jb

这个 Mock function 应该如何拦截 User#Foobar 对 Product#Price 的调用并返回字符串“MOCKED DATA”?

public void Mock(string mockedClass, string mockedFunction, string mockedReturn)
{
}

您应该使用依赖注入来解决这个问题。 User object 不应该知道Product的具体类型。 相反,您应该将Product封装在一个IProduct接口后面,并将一个IProduct或某种IProduct工厂传递给User构造函数。

例如:

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;
}

然后你可以创建你自己的“模拟”产品(我们应该称之为存根):

public class MockProduct : IProduct
{
    public MockProduct(string mockPrice)
    {
        _mockPrice = mockPrice;
    }

    public string Price()
    {
        return _mockPrice;
    }

    readonly string _mockPrice;
}

然后在您的测试中,您可以创建User并向其传递一个工厂方法来创建一个模拟IProduct

Func<IProduct> mockProductFactory = () => new MockProduct("MOCKED DATA");

User user = new User(mockProductFactory);

// Test user now.

虽然这实际上是一种存根形式(您已经使用过的术语)而不是 mocking - mocking 通常使用 mocking 框架完成,并使用反射来避免必须手动实现接口中的所有方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM