【问题标题】:How to: capture output from void method through the console?如何:通过控制台捕获 void 方法的输出?
【发布时间】:2018-04-29 00:48:43
【问题描述】:

我正在为质数程序编写一个测试用例。我正在尝试将我的PrimeEvaluator 方法的输出与我的expectedFactors1 字符串进行比较。 PrimeEvaluator 是一个 void 所以我试图从控制台读取输出。

public void PrimeTest()
{
    //arange
    int number = 738;
    string expectedFactors1 = "2,3,3,41";
    string actual;

    //act
    Primes.Program.PrimeEvaluator( number);
    actual = Console.ReadLine();

    //assert
    Assert.AreEqual(expectedFactors1,actual);           
}

当我运行我的单元测试时,什么也没有发生。我知道这可能是错误的,但有人能给我一些关于如何从PrimeEvaluator 捕获数字输出的见解吗?

【问题讨论】:

  • 显示主要评估者
  • 为什么不能让您的 PrimeEvaluator 方法返回答案,以便您可以以任何您认为合适的方式处理输出?只需让该方法返回一个整数列表即可。
  • void 是唯一看起来合适的返回类型,因为该类会检查多个条件。我试图使它成为一个 int 但它说“并非所有代码路径都返回一个值”
  • @MickyD 愚蠢的模拟方法?你知道单元测试是什么意思吗?在将他的主要评估方法与控制台输出相结合时,你给了他糟糕的建议。
  • @PmanAce 我不敢苟同。无论应用程序是否为 Web,用户界面测试均采用相同的尽职调查方法; WPF; WinForms 或控制台应用程序。一个 UI 就是一个 UI 就是一个 UI。测试破解打开 API 只是为了直接测试方法的唯一好处是增加测试代码覆盖率,顺便说一句,这在证明我的飞行管理计算机正常工作方面几乎没有什么作用,因为它没有测试整个用例。玩得开心嘲笑而不是测试真正重要的东西。 mickyd.wordpress.com/2016/05/25/…

标签: c# unit-testing console-application readline prime-factoring


【解决方案1】:

在这种特殊情况下,您可以使用Console.SetOut() 访问Console.Out 以拦截写入其中的内容。

public void PrimeTest() {        
    //stream and writer used to intercept console output
    using(var memoryStream = new MemoryStream()) {
        var writer = new StreamWriter(memoryStream);
        Console.SetOut(writer);

        //Arrange
        int number = 738;
        string expectedFactors1 = "2, 3, 3, 41";

        //Act
        Primes.Program.PrimeEvaluator(number);

        //Assert
        memoryStream.Position = 0; //reset position to read stream
        string actual = new StreamReader(memoryStream).ReadToEnd();
        Assert.AreEqual(expectedFactors1, actual);
    }
}

【讨论】:

  • 这正是我想要做的。测试用例现在运行,但返回失败。这就是我得到的回报:“消息:Assert.AreEqual 失败。预期:。实际:。“它在 Actual: 部分下没有显示任何内容,这意味着它可能不是从命令行读取。有什么想法吗?
  • @DavidKenyon96 忘记重置内存流位置。
  • 小记,你应该向他展示使用流的正确方法,通过显式关闭它们或使用 using 关键字...
【解决方案2】:

只需让您的 PrimeEvaluator 方法返回一个整数列表。然后您可以在不必解析控制台的情况下比较输出,这绝不是一个好主意。以下是如何更改方法以返回整数列表:

private static List<int> PrimeEvaluator(int number)
    {
        var result = new List<int>();

        // Take out the 2s
        while (number % 2 == 0)
        {
            result.Add(2);

            number /= 2;
        }

        // take out other primes
        int factor = 3;

        while (factor * factor <= number)
        {
            if (number % factor == 0)
            {
                result.Add(factor);

                number /= factor;
            }
            else
                factor += 2;
        }

        // if num is not 1, then whatever is left is prime.
        if (number > 1) result.Add(number);

        return result;
    }

然后在你的单元测试中调用它(你有两种比较方法):

List<int> primeFactorsList = PrimeEvaluator(738); // list variant
string primeFactorsString = string.Join(", ", primeFactorsList); // string variant

返回一个包含 4 个整数的列表:2、3、3、41

现在您的代码可以在库中重复使用,无需依赖控制台输出来获得答案。

附带说明一下,查看 .Net 中的 System.Math 代码以了解 Microsoft 如何实现可用的数学运算,源代码可用:System.Math

【讨论】:

  • 每次使用数字执行 Console.Write() 时,只需将其添加到整数列表并在方法末尾返回列表。
  • 似乎是一个好方法。你能告诉我PrimeEvaluator 末尾附近的 for 循环是什么样子吗?因为你不知道确切的数字是多少?
  • “不必解析控制台,这绝不是一个好主意” - 那么用户界面测试是个坏主意吗?我想不是。查看 RanorexSelenium。另外,如果PrimeEvaluator 是合同实现怎么办?如果只是为了适应单元测试而更改合同,合同可能会不高兴。无论如何,也许您应该为您的答案提供代码?
  • 如果解析控制台不是一个坏主意,在这种情况下我该怎么做才能将其保存到变量中?
  • @MickyD 这是同时测试表示逻辑和“业务”逻辑,这不仅仅是 单元测试 应该做的,还指出代码中不必要的耦合,因为它们'现在牢固地结合在一起。测试 UI 也不错,或者说是个坏主意,但测试 UI 以验证进行素数分解的函数是否返回正确的值 is, IMO。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-31
  • 2010-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多