简体   繁体   中英

Mocking a generic method with type constraints

I have a method I want to test in a class:

public class ClassUnderTest
{
  public T SetProperty<T>(string value, T object) where T : AnObjectType, IAnotherObjectType
  {
    object.property = value;
    return object;
  }
}

I'm using a mock object type that also implements IAnotherObjectTypelike this:

class MockObjectType: AnObjectType, IAnotherObjectType
{
  (implementation of IAnotherObjectType)
}

I want to set up a mock for my class, and CallBase for the method I'm testing, using my mock object, something like this:

string value = "value";
MockObjectType mockObject = new MockObjectType();

Mock<ClassUnderTest> mockClassUnderTest= new Mock<ClassUnderTest>(MockBehavior.Strict);
mockClassUnderTest.Setup(foo => foo.SetProperty<It.IsSubtype<IAnotherObjectType>>(
    It.IsAny<string>(), It.IsAny<It.IsSubtype<IAnotherObjectType>>()))
  .CallBase();

var result = mockClassUnderTest.Object.SetProperty(value, mockObject);

Assert.That(result.property, Is.EqualTo(value));

But this code won't compile, showing the error:

The type ' Moq.It.IsSubtype<IAnotherObjectType> ' cannot be used as type parameter 'T' in the generic type or method ' SetProperty<T>(string, T) '. There is no implicit reference conversion from ' Moq.It.IsSubtype<IAnotherObjectType> ' to ' AnObjectType '

What am I doing wrong here? I assume this is an issue with the syntax of some kind, so how should I express what I'm trying to do here?

EDIT I've clarified the relationship between the object types that the constraints specify.

I should also clarify that the test I've described is a simplified one. I also want to verify other behaviours of the method, ie calling other mocked methods, etc. Using a mock of the class under test is required for this verification. I just want to know how to CallBase for this method on the mocked class.

Do not mock the subject under test. Mock the dependency to behave as expected when the test is exercised

//Arrange
string value = "value";
var mockObject = new Mock<AnObjectType>();
mockObject.As<IAnotherObjectType>().SetupAllProperties();
// now the mock also implements IAnotherObjectType
mockObject.SetupAllProperties();


ClassUnderTest classUnderTest = new ClassUnderTest();

//Act
var result = classUnderTest.SetProperty(value, mockObject.Object);

//Assert
Assert.That(result.property, Is.EqualTo(value));

Reference Moq Quickstart

It could be tested without mocking the actual method under the test

    public void SetPropertySetsValue()
    {
        string value = "value";
        MockObjectType mockObject = new MockObjectType(); // or create object of ObjectType
        ClassUnderTest classUnderTest = new ClassUnderTest();


        var result = classUnderTest.SetProperty(value, mockObject);
        Assert.AreEqual(value, mockObject.property);
    }

That would verify the value was set by SetProperty() method correctly or not.

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