简体   繁体   English

如何为返回数组的函数创建单元测试

[英]How to create unit test for function that returns an array

I am a newbie dev and I am trying to create a unit test for the code below.我是一个新手开发人员,我正在尝试为下面的代码创建一个单元测试。 Mind you the code isnt perfect as I have written it in the context of what I have read/learnt so far.请注意,代码并不完美,因为我是在迄今为止阅读/学到的内容的上下文中编写的。 Its a program meant to display the prime factors of a number entered by a user.它是一个程序,旨在显示用户输入的数字的质因数。 In my unit test file, i created an object of class PFGen but for some reason i am not able to use the object to call method PrimeFactors (which returns an array).在我的单元测试文件中,我创建了一个 PFGen 类的对象,但由于某种原因,我无法使用该对象来调用方法 PrimeFactors(它返回一个数组)。 Will appreciate all help.将感谢所有帮助。

using System;
using static System.Console;
using System.Diagnostics;
using System.IO;

namespace PrimeFactorsGen
{
    public class PFGen
    {
        public static Array PrimeFactors(int number)
        {
            int[] pf = new int[10];
            int position = 0;

            for(int div = 2; div <= number; div++)
            {
                while(number % div == 0)
                {
                    pf[position] = div;
                    number = number / div;
                    position = position + 1;
                }
            }

            return pf;
        }

        public static void RunPrimeFactor()
        {
            Write("Please enter a value to calculate prime factors: ");
            if (int.TryParse(ReadLine(), out int number)){
                if(number >= 2)
                {
                    WriteLine($"The prime factors of {number} are: ");
                    foreach(var entry in PrimeFactors(number))
                    {
                        Write($"{entry}, ");
                    }
                }
                else
                {
                    WriteLine("Enter a number greater than 2 next time!");
                }
            }else
            {
                WriteLine("Enter a valid number");
            }
        }

        static void Main(string[] args)
        {
            Trace.Listeners.Add(new TextWriterTraceListener(File.CreateText("log.txt")));

            Trace.AutoFlush = true;
            Trace.WriteLine("Trace is listening...");

            RunPrimeFactor();
        }
    }
}

Thanks for the help so far.感谢你目前的帮助。 I have been able to access PrimeFactors by calling it directly with PFGen.我已经能够通过直接使用 PFGen 调用来访问 PrimeFactors。 The unit test code is below.单元测试代码如下。 It passed.它通过了。

using System;
using Xunit;
using PrimeFactorsGen;

namespace FactorialUnitTest
{
    public class UnitTest1
    {
        [Fact]
        public void Test1()
        {
            //arrange
            int number = 42;
            int[] expected = { 2, 3, 7, 0, 0, 0, 0, 0, 0, 0 };
            //act
            var actual = PFGen.PrimeFactors(number);
            //assert
            Assert.Equal(actual,expected);
        }
    }
}

This is a great use case for XUnit's Theory attribute.这是 XUnit 的Theory属性的一个很好的用例。 Decorating a test method with the Theory attribute means that you can run it multiple times with different inputs and expected outputs.使用Theory属性装饰测试方法意味着您可以使用不同的输入和预期输出多次运行它。

First, I've taken the liberty of changing the PrimeFactors method's return value from an array to a List<int> ( see Microsoft documentation of this class ).首先,我冒昧地将 PrimeFactors 方法的返回值从数组更改为List<int>请参阅 Microsoft 此类的文档)。 This has two advantages over an array:与数组相比,这有两个优点:

  • An array's length is fixed when it is declared, whereas a List<T> grows and shrinks as items are added or removed - this eliminates the misleading zeroes in the unused elements of the array (zero isn't a prime factor of anything).数组的长度在声明时是固定的,而List<T>随着项目的添加或删除而增长和缩小 - 这消除了数组未使用元素中的误导性零(零不是任何事物的主要因素)。
  • A List<T> is type safe - we know that every element in the list is of type T, and any attempt to put something that's not of type T into the list will result in a compile error. List<T>是类型安全的——我们知道列表中的每个元素都是 T 类型,任何将非 T 类型的东西放入列表的尝试都会导致编译错误。
public static List<int> PrimeFactors(int number)
{
    //int[] pf = new int[10];
    var pf = new List<int>();
    //int position = 0;

    for (int div = 2; div <= number; div++)
    {
        while (number % div == 0)
        {
            //pf[position] = div;
            pf.Add(div);
            number = number / div;
            //position = position + 1;
        }
    }

    return pf;
}

Anyway, back to the actual question...无论如何,回到实际问题......

There are a few different ways of passing test data to your Theory test, but the simplest is probably to add InlineData attributes to your test method.有几种不同的方法可以将测试数据传递给您的Theory测试,但最简单的方法可能是将InlineData属性添加到您的测试方法中。 The InlineData attribute accepts the same parameters as your test method, and passes those parameters into your test method. InlineData属性接受与您的测试方法相同的参数,并将这些参数传递到您的测试方法中。

This is the unit test I've written:这是我写的单元测试:

[Theory]
[InlineData(2, new int[] { 2 })]
[InlineData(3, new int[] { 3 })]
[InlineData(4, new int[] { 2, 2 })]
[InlineData(5, new int[] { 5 })]
[InlineData(6, new int[] { 2, 3 })]
[InlineData(7, new int[] { 7 })]
[InlineData(8, new int[] { 2, 2, 2 })]
[InlineData(9, new int[] { 3, 3 })]
[InlineData(10, new int[] { 2, 5 })]
[InlineData(11, new int[] { 11 })]
[InlineData(12, new int[] { 2, 2, 3 })]
[InlineData(13, new int[] { 13 })]
[InlineData(14, new int[] { 2, 7 })]
[InlineData(15, new int[] { 3, 5 })]
[InlineData(16, new int[] { 2, 2, 2, 2 })]
[InlineData(17, new int[] { 17 })]
[InlineData(18, new int[] { 2, 3, 3 })]
[InlineData(19, new int[] { 19 })]
[InlineData(20, new int[] { 2, 2, 5 })]
[InlineData(21, new int[] { 3, 7 })]
[InlineData(22, new int[] { 2, 11 })]
[InlineData(23, new int[] { 23 })]
[InlineData(24, new int[] { 2, 2, 2, 3 })]
[InlineData(25, new int[] { 5, 5 })]
[InlineData(42, new int[] { 2, 3, 7 })]
public void PrimeFactorsTest(int input, int[] primeFactors)
{
    // Arrange
    var expected = new List<int>(primeFactors);

    // Act
    var actual = PFGen.PrimeFactors(input);

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

The test method accepts two parameters测试方法接受两个参数

  • an integer called input - this is the number we want to find the prime factors of.一个叫做input的整数 - 这是我们想要找到质因数的数字。
  • an array called primeFactors - this is an array of the prime factors that we expect the PrimeFactors method to return for the given value of input .一个名为primeFactors的数组 - 这是一个素数数组,我们希望PrimeFactors方法为给定的input值返回这些素数。

Each InlineData attribute passes the same two parameters into the test method, for example每个InlineData属性都将相同的两个参数传递给测试方法,例如

[InlineData(42, new int[] { 2, 3, 7 })]

This will pass 42 to the test method's input parameter, and an array of 2, 3 and 7 to the test method's primeFactors parameter, to indicate that when we pass 42 to the PrimeFactors method, we expect the returned prime factors to be 2, 3 and 7.这会将 42 传递给测试方法的input参数,并将 2、3 和 7 的数组传递给测试方法的primeFactors参数,以表明当我们将 42 传递给PrimeFactors方法时,我们期望返回的素因子为 2、3和 7。

If you want to add more inputs and expected outputs to the test, just add more InlineData attributes.如果要向测试添加更多输入和预期输出,只需添加更多InlineData属性。

Don't use the Array type.不要使用Array类型。 EIther use the type-safe int[] or the variable length List<int> .或者使用类型安全的int[]或可变长度List<int> You can check a collection with CollectionAssert.AreEqual()您可以使用CollectionAssert.AreEqual()检查集合

For example in the test method例如在测试方法中

List<int> actual = PrimeFactors(42);
int[] expected = new int[] { 2, 3, 7 };
CollectionAssert.AreEqual(expected, actual);

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

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