简体   繁体   中英

Create an Unit Test for Generic Method

I have the following class:

public class Range<T> where T : IComparable<T> {

  public T Minimum { get; set; }
  public T Maximum { get; set; }

  public Range(T minimum, T maximum) {
    Minimum = minimum;
    Maximum = maximum;
  }

  public Boolean Contains(T value) {
    return (Minimum.CompareTo(value) <= 0) && (value.CompareTo(Maximum) <= 0);
  }

}

I am using XUnit to create my Unit Tests ...

How should I test the Contains method that has T?

As has been stated, you could test it with an int which might look something like this:

var range = new Range<int>(minimum: 3, maximum: 7);
Assert.IsTrue(range.Contains(5));

You need to create an instance of an IComparable and for thoroughness (true unit testing) I would suggest a mocking library with the ability to verify calls. I would probably use something like Moq. You will need an object that implements the interface, which you might have already or you could create a test one with no actual implemetation.

public class YourObject : IComparable<YourObject>
{
  public virtual int CompareTo(YourObject other)
  {
    throw new NotImplementedException();
  }
}

I would make a subtle change your Range code just a bit for consistency:

public class Range<T> where T : IComparable<T>
{

  public T Minimum { get; set; }
  public T Maximum { get; set; }

  public Range(T minimum, T maximum)
  {
    Minimum = minimum;
    Maximum = maximum;
  }

  public Boolean Contains(T value)
  {
    return (Minimum.CompareTo(value) <= 0) && (Maximum.CompareTo(value) >= 0);
  }
}

The end result is identical but it makes things a bit easier while setting up the mocks. Or you could go with value.CompareTo on both accounts. Either way it would add a little more consistency.

The test code would look a little like this:

  var min = new Mock<YourObject>();
  var max = new Mock<YourObject>();
  var val = new Mock<YourObject>();

  var range = new Range<YourObject>(min.Object, max.Object);

  min.Setup(m => m.CompareTo(It.IsAny<YourObject>())).Returns(-1);
  max.Setup(m => m.CompareTo(It.IsAny<YourObject>())).Returns(1);
  Assert.True(range.Contains(val.Object));

  min.Setup(m => m.CompareTo(It.IsAny<YourObject>())).Returns(0);
  max.Setup(m => m.CompareTo(It.IsAny<YourObject>())).Returns(1);
  Assert.True(range.Contains(val.Object));

  min.Setup(m => m.CompareTo(It.IsAny<YourObject>())).Returns(-1);
  max.Setup(m => m.CompareTo(It.IsAny<YourObject>())).Returns(0);
  Assert.True(range.Contains(val.Object));


  min.Setup(m => m.CompareTo(It.IsAny<YourObject>())).Returns(1);
  max.Setup(m => m.CompareTo(It.IsAny<YourObject>())).Returns(1);
  Assert.False(range.Contains(val.Object));

  min.Setup(m => m.CompareTo(It.IsAny<YourObject>())).Returns(-1);
  max.Setup(m => m.CompareTo(It.IsAny<YourObject>())).Returns(-1);
  Assert.False(range.Contains(val.Object));

Now you are testing your Range class's Contains method and not the object's ability to return the correct value when it's CompareTo is called.

Happy Coding!

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.

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