[英]How do I fake the return of a built-in method in C# unit test?
我有一个公共 static 方法,它使用随机 class 的 object 来生成 Z157DB7DF53002357551ZD366 然后将 integer 设为 List 的索引。 我想测试方法的逻辑,同时控制随机对象的 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];
}
}
从我的 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);
}
}
我希望 mockRandom.Next 每次在此测试中运行时返回 2 。 显然,这不是这样做的方法。 我一直在搜索示例,但它们似乎都使用 object 上的方法和实例方法而不是 static 方法。
在对使用它的方法进行单元测试时,如何控制内置方法返回的内容?
您可以使用从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;
}
考虑重构以实现更可维护的设计
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];
}
}
这允许更灵活地使用和测试主题 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);
}
}
理想情况下,如果将此生成器用作服务,它应该有自己的抽象
public interface IRandomGenerator {
string GetRandomListMember(List<string> anyStringList);
}
public class RandomGenerator : IRandomGenerator {
//...omitted for brevity
}
这样它就可以在需要的地方显式注入,而不是静态地用作紧密耦合的依赖项,这可以被认为是代码异味。
我在评论中的建议示例:
[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.