Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I Write Tests for Argument Exceptions?

When applying TDD, do you create tests that verify expected exceptions for arguments (ArgumentException, ArgumentNullException, InvalidOperation, etc.) or just ones that are "known", for example, CustomerDelinquentException ?

What about equals, gethashcode overrides? how would i test gethashcode?

Thanks

like image 314
Marco Avatar asked Jun 25 '26 05:06

Marco


1 Answers

I always test for any exceptions I throw in my method, including ArgumentNullException, ArgumentException, etc. I just find it's best to test these and they're easy to write. That way if someone ever removes those guards, the tests would break and you'd know.

    [TestMethod]
    [ExpectedException(typeof(ArgumentNullException))]
    public void ToSetOnNullThrows()
    {
        List<string> list = null;
        var target = list.ToHashSet();
    }

As far as GetHashCode() and Equals() i test these as well if you override them. For GetHashCode() an easy test is to create two equivalent objects (same values used in the hash code) and prove that the hash codes both objects generate are the same.

    [TestMethod]
    public void GetHashCodeSameKeysAreSameTest()
    {
        var key = new CompositeKey<string, int>("A", 13);
        var otherKey = new CompositeKey<string, int>("A", 13);

        Assert.AreEqual(key.GetHashCode(), otherKey.GetHashCode());
    }

You can try to test that two non-equivalent objects return different hash codes, but you'd have to make sure the values you use aren't simply a collision. This largely depends on the algorithm you code in GetHashCode().

    [TestMethod]
    public void GetHashCodeDifferentKeysAreMostLikelyDifferentTest()
    {
        var key = new CompositeKey<string, int>("A", 13);
        var otherKey = new CompositeKey<string, int>("A", 14);

        Assert.AreNotEqual(key.GetHashCode(), otherKey.GetHashCode());
    }

For Equals() test that two equivalent objects with the same fields return true on Equals() and false on two non-equivalent objects.

    [TestMethod]
    public void EqualsTest()
    {
        var key = new CompositeKey<string, int>("A", 13);
        var otherKey = new CompositeKey<string, int>("A", 13);

        Assert.IsTrue(key.Equals(otherKey));
    }

    [TestMethod]
    public void NotEqualsTest()
    {
        var key = new CompositeKey<string, int>("A", 13);
        var otherKey = new CompositeKey<string, int>("A", 15);

        Assert.IsFalse(key.Equals(otherKey));
    }

For even more fun, I like to unit tests DateTime dependent stuff too. This is somewhat harder, but if a method's behavior depends on DateTime i still want to unit test them. So you can create a DateTime generator delegate that defaults to returning DateTime.Now but have it so that you can set the generator to a specific DateTime. Helps a lot with coverage in my line of work since I'm in the financial industry and a lot of logic depends on pre-market, post-market hours, etc...

public class SomeClassThatDependsOnCurrentTime
{
    internal Func<DateTime> NowGenerator { get; set; }

    public SomeClassThatDependsOnCurrentTime()
    {
        // default in constructor to return DateTime.Now
        NowGenerator = () => DateTime.Now;
    }

    public bool IsAfterMarketClose()
    {
        // call the generator instead of DateTime.Now directly...
        return NowGenerator().TimeOfDay > new TimeSpan(16, 0, 0);
    }
}

Then you just set up a unit test to inject a specific date time.

like image 198
James Michael Hare Avatar answered Jun 27 '26 19:06

James Michael Hare



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!