如何在C#单元测试中手动启用功能

发布于 2025-02-03 08:30:14 字数 1639 浏览 2 评论 0原文

我正在尝试创建自己的模拟功能。我知道有量量的存在,但我真的很想实现这一目标。

我不知道我如何创建模拟功能来使用户#Foobar的“产品#价格”的呼叫以单位测试用户#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#中不知道。

这是问题的净小提琴:

https://dotnetfiddle.net/8re2jb

这个模拟功能应该做什么拦截用户#Foobar的呼叫呼叫产品#价格并返回字符串“模拟数据”?

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

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 
quot;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)
{
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

む无字情书 2025-02-10 08:30:14

您应该使用依赖注入来解决此问题。 用户对象不应知道product的具体类型。相反,您应该在iProduct接口后面封装product接口,然后传递到user structionor iproduct或某种类型iProduct工厂。

例如:

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.

尽管这确实是一种固执的形式(您已经使用过的术语)而不是模拟 - 通常使用模拟框架进行模拟,并使用反思来避免在一个模拟框架中手动实现所有方法界面。

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 
quot;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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文