Necoras Necoras - 1 month ago 25
C# Question

Unable to typecast Mock's object when using the AWS SDK and Moq

I'm attempting to write unit tests around a service which will manage communication with various SQS queues. I'm unable to inject Mocked versions of the IAmazonSQS into my class. I have the following constructor:

private AmazonSQSClient client;

public SqsQueue(IAmazonSQS client, string queueUrl)
{
this.client = (AmazonSQSClient)client;
this.queueUrl = queueUrl;
}


The problem line is the assignment to this.client. I get this exception:
Additional information: Unable to cast object of type 'Castle.Proxies.IAmazonSQSProxy' to type 'Amazon.SQS.AmazonSQSClient'.
When I change that line to this:

this.client = client as AmazonSQSClient;


this.client is set to null.

This is the relevant Unit Test code:

public void Setup()
{
this.mockClient = new Mock<IAmazonSQS>();
this.queueUrl = "testUrl";
}

public void GetMessageCount_WhenMessagesExist_ReturnsCount()
{
// Arrange
var sqsQueue = new SqsQueue<IMessage>(this.mockClient.Object, this.queueUrl); // Calls into the constructor above.
}


Am I missing something obvious here?

Answer

I know you self-answered, but I figured I'd give my answer as well.

The problem is that your constructor is accepting an interface, then you are casting that interface to a discrete class. While this works for normal operations, it will not work in your unit testing, because your actual discrete class is not an AmazonSQSClient and has no relationship to it. The only commonality between AmazonSQSClient and your mock object is that they both implement the IAmazonSQSClient interface.

To use the Amazon clients, all you need is the interface. So, change your member variable to the interface, and avoid the casting:

private IAmazonSQSClient client;

public SqsQueue(IAmazonSQS client, string queueUrl)
{
    this.client = client;
    this.queueUrl = queueUrl;
}
Comments