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). 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. 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. Decorating a test method with the Theory
attribute means that you can run it multiple times with different inputs and expected outputs.
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 ). This has two advantages over an array:
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>
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. 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. The InlineData
attribute accepts the same parameters as your test method, and passes those parameters into your test method.
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
input
- this is the number we want to find the prime factors of.primeFactors
- this is an array of the prime factors that we expect the PrimeFactors
method to return for the given value of input
. Each InlineData
attribute passes the same two parameters into the test method, for example
[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.
If you want to add more inputs and expected outputs to the test, just add more InlineData
attributes.
Don't use the Array
type. EIther use the type-safe int[]
or the variable length List<int>
. You can check a collection with CollectionAssert.AreEqual()
For example in the test method
List<int> actual = PrimeFactors(42);
int[] expected = new int[] { 2, 3, 7 };
CollectionAssert.AreEqual(expected, actual);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.