2

I have this abstract class, that I want to test. I want to ensure that when SomeMethod is invoked, ValidateStronglyTypedData is called.

public abstract class SomeAbstractClass<TDataType> where TDataType : class
{
    public ResultType SomeMethod(string someParam)
    {
        TDataType tDataType = convert(someParam);
        this.ValidateStronglyTypedData(tDataType);
    }

    protected abstract ResultType ValidateStronglyTypedData(TDataType stronglyTypedData);
}

I've got this:

// Arrange
var mockSomeAbstractClass = new Mock<SomeAbstractClass<TestJsonDataType>>();
var testData = "{ 'testProperty': 'test value' }";
mockSomeAbstractClass.Protected().Setup<ValidationResult>("ValidateStronglyTypedData", It.IsAny<TestJsonDataType>());

// Act
mockSomeAbstractClass.Object.ValidateData(testData);

// Assert
mockSomeAbstractClass.Protected().Verify("ValidateStronglyTypedData", Times.Once(), It.IsAny<TestJsonDataType>());

but at runtime it complains that it cannot find the method. Is it because the protected method is abstract? It fails on the setup with:

System.ArgumentException: 'Use ItExpr.IsNull rather than a null argument value, as it prevents proper method lookup.'

I have tried ItExpr and still doesn't work. I am guessing it has to do with the class being generic.

hyankov
  • 4,049
  • 1
  • 29
  • 46
  • Possible duplicate of [How to unit test abstract classes](https://stackoverflow.com/questions/7966439/how-to-unit-test-abstract-classes) – nilsK Sep 25 '18 at 13:48
  • Why would I create a mock implementation of the abstract class, when I use `Moq`?! That's what the `mockSomeAbstractClass` object is supposed to be. – hyankov Sep 25 '18 at 13:50
  • Can you include the actual error message? – Dan Wilson Sep 25 '18 at 13:50
  • 1
    As nvoigt said, why not testing the actual implementation instead of testing the abstract class? – Zysce Sep 25 '18 at 13:53
  • Because I want to directly test the behavior that the abstract defines, without going through the trouble of 'statically' defining a fake implementation. Isn't the `Moq` at runtime a fake implementation? – hyankov Sep 25 '18 at 13:57
  • 4
    You should mock dependencies, not the thing you're testing. – mason Sep 25 '18 at 13:58
  • Oh now that you put it this way, it made sense. – hyankov Sep 25 '18 at 14:00

1 Answers1

3

I'd say why bother with all that mocking when you can just do the real thing?

public class TestClass
{
    private class DerivedTest : SomeAbstractClass<string>
    {
        public bool WasCalled { get; private set; }

        protected override ResultType ValidateStronglyTypedData(string stronglyTypedData)
        {
            this.WasCalled = true;
        }
    }

    [YourFavoriteFrameWorkAttributeForTestMethod]
    public void TestMethod()
    {
         // arrange
         var instance = new DerivedTest();

         // act
         var result = instance.SomeMethod("test");

         // assert
         Assert.IsTrue(instance.WasCalled);    
    }
}
nvoigt
  • 75,013
  • 26
  • 93
  • 142
  • Because I thought I'd get that 'for free' with `Moq`. – hyankov Sep 25 '18 at 13:53
  • 2
    It seems way more complicated with Moq. Mocking is a tool, to use *when you need it*. Make sure you don't treat everything as a nail, just because you have "hammer" installed. Sometimes, not using every tool in your belt is the easiest way. – nvoigt Sep 25 '18 at 13:54