简体   繁体   English

如何在 C# 单元测试中伪造内置方法的返回?

[英]How do I fake the return of a built-in method in C# unit test?

I have a public static method that uses an object of Random class to generate an integer.我有一个公共 static 方法,它使用随机 class 的 object 来生成 Z157DB7DF53002357551ZD366 The integer is then made the index of a List.然后将 integer 设为 List 的索引。 I want to test the logic of the method while having control over what a random object's Next method returns.我想测试方法的逻辑,同时控制随机对象的 Next 方法返回的内容。

public class RandomGenerator
  {

    // a static method which produces a random selection from a List
    public static string GetRandomListMember(List<string> anyStringList)
    {
      Random rand = new Random();
      int randomInt = rand.Next(anyStringList.Count);
      return anyStringList[randomInt];
    }
  }

From my MSTest file:从我的 MSTest 文件中:

[TestClass]
  public class RandomGeneratorSpec
  {
    [TestMethod]
    public void GetRandomListMember_ListOfStrings()
    {
      List<string> strings = new List<string> { "red", "yellow", "green" }; 

      Mock<Random> mockRandom = new Mock<Random>();
      mockRandom.Setup(rand => rand.Next(strings.Count)).Returns(() => 2); // 2!

      string result = RandomGenerator.GetRandomListMember(strings);

      Assert.AreEqual("green", result);
    }
  }

I want mockRandom.Next to return 2 every time it runs in this test.我希望 mockRandom.Next 每次在此测试中运行时返回 2 。 Obviously, this isn't the way to do it.显然,这不是这样做的方法。 I've been searching through examples, but they all seem to utilize methods on the object and with instance methods instead of static methods.我一直在搜索示例,但它们似乎都使用 object 上的方法和实例方法而不是 static 方法。

How do I control what a built-in method returns while unit testing a method that utilizes it?在对使用它的方法进行单元测试时,如何控制内置方法返回的内容?

You could create your own Random class locally with whatever methods you need to redefine from the System.Random class.您可以使用从System.Random class 重新定义的任何方法在本地创建自己的Random class。

class Program
{
    static void Main(string[] args)
    {
        var rand = new Random();
        int next = rand.Next(); // uses my local Random class.
    }
}

class Random
{
    public int Next() => 2;
}

Consider refactoring to allow a more maintainable design考虑重构以实现更可维护的设计

public class RandomGenerator {
    private readonly Random random;

    public RandomGenerator(Random random = default(Random)) {
        this.random = random ?? new Random();
    }

    public string GetRandomListMember(List<string> anyStringList) {
        int randomInt = random.Next(anyStringList.Count);
        return anyStringList[randomInt];
    }
}

Which allows more flexibility with using and testing the subject class这允许更灵活地使用和测试主题 class

[TestClass]
public class RandomGeneratorSpec {
    [TestMethod]
    public void GetRandomListMember_ListOfStrings() {
        //Arrange
        List<string> strings = new List<string> { "red", "yellow", "green" };
        string expected = "green";
        Mock<Random> mockRandom = new Mock<Random>();
        mockRandom.Setup(rand => rand.Next(strings.Count)).Returns(() => 2); // 2!
        var subject = new RandomGenerator(mockRandom.Object);

        //Act
        string actual = subject.GetRandomListMember(strings);

        //Assert
        Assert.AreEqual(expected, actual);
    }
}

Ideally if this generator is to be used as a service, it should have its own abstraction理想情况下,如果将此生成器用作服务,它应该有自己的抽象

public interface IRandomGenerator {
    string GetRandomListMember(List<string> anyStringList);
}

public class RandomGenerator : IRandomGenerator {
    //...omitted for brevity
}

so that it can be injected explicitly where needed and not be used statically as a tightly coupled dependency that can be considered a code smell.这样它就可以在需要的地方显式注入,而不是静态地用作紧密耦合的依赖项,这可以被认为是代码异味。

An example of my suggestion in the comment:我在评论中的建议示例:

[TestClass]
public class RandomGeneratorSpec
{
    [TestMethod]
    public void GetRandomListMember_ListOfStrings()
    {
        List<string> strings = new List<string> { "red", "yellow", "green" }; 

        string result = RandomGenerator.GetRandomListMember(strings);

        Assert.IsTrue(strings.Contains(result));
    }
}

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

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