Home > Back-end >  Testing an infinite sequence with NUnit, but only a finite sequence must be checked
Testing an infinite sequence with NUnit, but only a finite sequence must be checked

Time:05-25

I have an Extension Method that extract the numbers in a list of strings (bbb1, da21ds, dsa231djsla90 ==> 1, 21, 23190):

    public static int[] GetContainedNumbers(this string[] source)
    {
        if (source == null) throw new ArgumentNullException();
        int[] result = new int[] {};
        
        foreach (var s in source)
        {
            string onlyNumbers = new String(s.Where(Char.IsDigit).ToArray());
            if (String.IsNullOrEmpty(onlyNumbers)) throw new ArgumentException();
            int extractedNumber = Int32.Parse(onlyNumbers);
            
            result = result.Concat(new int[] { extractedNumber }).ToArray();
        }
        
        return result;
    }

I need to make a test with NUnit. The request is to make a test with an infinite sequence of strings (a1z, a2z, a3z, ...), but the output only needs to check the first 100 numbers.

Currently I have no idea what I'm supposed to do. My starting idea was to create a test like this:

        int[] expectedResult = Enumerable.Range(0, 99).ToArray();
        string[] source = new string[] {};
        int n = 0;
        
        while (true)
        {
            if (n == 99) break;
            source = source.Concat(new string[] { "a"   n   "z" }).ToArray();
            n  ;
        }
        
        Assert.AreEqual(expectedResult, source.GetContainedNumbers());

But it doesn't really make sense since the array is finite and not infinite. I don't know what it means to create an infinite list of things and how I should create it nor testing it.

I can edit the Extension Method if needed. Thanks in advance for any help and sorry if my english is quite broken.


The first task is to make the Extension method itself, which I have resolved above. It can be modified, but it must resolve this piece of code (which I can't edit):

foreach (var d in new[] { "1qui7", "q8u8o", "-1024", "0q0ua0" }.GetContainedNumbers())
        {
            Console.WriteLine("{0}, ", d);
            var strings = new [ ] { "1qui7" , " q8u8o " , " −1024" , " 0 q0ua0 " };
        }

Expected output: 17, 88, 1024, 0,

CodePudding user response:

I believe the purpose of this exercise is to investigate lazy evaluation.

Currently your method accepts a string[] and returns an int[] - but there's nothing in the question that says it has to do that.

If instead you were to write an extension method accepting an IEnumerable<string> and returning an IEnumerable<int>, then you could accept an infinite sequence of elements and return a corresponding infinite sequence of outputs, that is lazily evaluated: when the caller requests the next output element, you in turn request the next input element, process it, and yield an output. C# makes all of this quite straightforward with iterator blocks.

So I would expect a method like this:

public static IEnumerable<int> GetContainedNumbers(IEnumerable<string> source)
{
    foreach (string inputElement)
    {
        int outputElement = ...; // TODO: your logic here
        yield return output;
    }
}

Now to test this, you can either use iterator blocks again to generate genuinely infinite sequences, or you could test against an effectively infinite sequence using LINQ, e.g.

IEnumerable<string> veryLargeInput = Enumerable
    .Range(0, int.MaxValue)
    .Select(x => $"a{x}z");

The truly infinite version might be something like:

IEnumerable<string> infiniteSequence = GetInfiniteSequence();
...
private static IEnumerable<string> GetInfiniteSequence()
{
    int value = 0;
    while (true)
    {
        yield return $"x{value}z";
        // Eventually this will loop round from int.MaxValue to
        // int.MinValue. You could use BigInteger if you really wanted.
        value  ;
    }
}

When testing the result, you'll want to take the first 100 elements of the output. For example:

var input = GetInfiniteSequence(); // Or the huge Enumerable.Range
var output = input.GetContainedNumbers(); // This is still infinite
var first100Elements = output.Take(100).ToList();
// Now make assertions against first100Elements
  • Related