2

The goal of my UnitTest is to validate if the ValidateEquality will return false for two unequal instances of a FooClass.

I'm asking only about the arrange part of the unit test while the act and assert are not important.

I have a builder facade that is creating a fake instances of the desired FooClass (BuilderFacade.BuildFooClass()) and real service api that creating a real instances of it (GetFooClassFromSomewhere).

The problem is that the BuilderFacade creates a random E_BooEnum value, and in order for this unit test will pass every time I need to instantiate the foolClass2 with a BooEnum value that is different from the fooClass1's BooEnum random value.

How to initiate the BooEnum with a value except of the fake instance value?

[TestMethod]
public void AreEqual_DifferentBooEnum_ShouldReturnFalse()
{
    //Arrange:
    FooClass fooClass1 = BuilderFacade.BuildFooClass();
    FooClass fooClass2 = GetFooClassFromSomewhere();
    fooClass2.BooEnum = ! fooClass1.BooEnum // <--------Every possible value is OK besides the `fooClass1.BooEnum` value.

    ...
    //Act
    var result = service.ValidateEquality(fooClass1, fooClass2);
    //Assert
    Assert.IsFalse(result);
}

public class BuilderFacade
{
    public static FooClass BuildFooClass()
    {
        Random rand = new Random();
        E_BooEnum booEnum = (E_BooEnum)rand.Next(System.Enum.GetNames(typeof(E_BooEnum)).Length);
        return new FooClass()
        {
            BooEnum = booEnum
        };
    }
}

The model:

public class FooClass
{
    public E_BooEnum BooEnum { get; set; }
    public override in GetHashCode()
    {
        unchecked
        {
            int hash = 17;
            hash = hash * 31 + this.BooEnum.GetHashCode();
        }
    }
 }
Shahar Shokrani
  • 7,598
  • 9
  • 48
  • 91

2 Answers2

3

Use fixed values instead of random values.
In tests you want to be in control of what values are passed to the class under the test.

Add method to the builder which accepts enum value and set it to the FooClass

public class FooBuilder
{
    private readonly BooEnum _boo;

    public FooBuilder(BooEnum boo)
    {
        _boo = boo;
    }

    public FooClass Create()
    {
        return new FooClass()
        {
            BooEnum = _boo
        };
    }
}

Not sure about MSTest, but for example in xUnit you can use inline argument for tests where you can provide all enum values with expected validation result

[Theory]
[InlineData(BooEnum.First, BooEnum.Second, false)]
[InlineData(BooEnum.Second, BooEnum.First, false)]
[InlineData(BooEnum.First, BooEnum.First, true)]
[InlineData(BooEnum.Second, BooEnum.Second, true)]
public void AreEqual_DifferentBooEnum_ShouldReturnFalse(BooEnum first, BooEnum second, bool expected)
{
    var firstFoo = new FooBuilder(first).Create();
    var secondFoo = new FooBuilder(second).Create();

    var actual = service.ValidateEquality(firstFoo, secondFoo);

    actual.Should().Be(expected);
}
Fabio
  • 31,528
  • 4
  • 33
  • 72
0

Based on this answer:

int enumLength = System.Enum.GetNames(typeof(E_BooEnum)).Length;
fooClass2.BooEnum = (BooEnum)GiveMeANumberExcept(enumLength, (int)fooClass1.BooEnum);

Generate an array without the except index and return one of its values:

private int GiveMeANumberExcept(int enumLength, int expectIndex)
{
    var exclude = new HashSet<int>() { expectIndex };
    var range = Enumerable.Range(0, enumLength).Where(i => !exclude.Contains(i));

    var rand = new System.Random();
    int index = rand.Next(0, enumLength - exclude.Count);
    return range.ElementAt(index);
}
Shahar Shokrani
  • 7,598
  • 9
  • 48
  • 91