1

I am creating a C# web API 2.0. along with a Test project. The API works fine. When I run the test project and hover over the contentResult, which is the value returned from the API, it has the correct value. However, all the Assert statements fail. In the code below I am returning an object, DeliveryCode. Even when I return string, I get the same error.

The controller:

public class CodeGeneratorController : ApiController
{
    ICheckCodeExist _checkCodeExist;
    IGenerateBrandNewCode _generateBrandNewCode;
    IGenerateFromExistingCode _generateFromExistingCode;
    IDeliveryCode _deliveryCode;

    public CodeGeneratorController(ICheckCodeExist checkCodeExist, IGenerateBrandNewCode generateBrandNewCode, IGenerateFromExistingCode generateFromExistingCode, IDeliveryCode deliveryCode)
    {
        _checkCodeExist = checkCodeExist;
        _generateBrandNewCode = generateBrandNewCode;
        _generateFromExistingCode = generateFromExistingCode;
        _deliveryCode = deliveryCode;
    }

    [HttpGet]
    [Route("api/CodeGenerator/{percentage}")]
    public IHttpActionResult Get(int percentage)
    {
        if (_checkCodeExist.IsCodeAvailable(percentage))
        {
            _deliveryCode.Code = _generateFromExistingCode.GetDeliveryCode();                   
            return Ok(_deliveryCode);
        }
        else
        {
            _deliveryCode.Code = _generateBrandNewCode.GetDeliveryCode();
            return Ok(_deliveryCode);
        }            
    }
}

Concrete class 1:

public class GenerateFromExistingCode : IGenerateFromExistingCode
{
    public string GetDeliveryCode()
    {
        return "XYZ456";
    }
}

Concrete class 2:

public class GenerateBrandNewCode : IGenerateBrandNewCode
{
    public string GetDeliveryCode()
    {
        return "ABC123";
    }
}

Test

[TestMethod]
public void GetDeliveryCodeWithPercentage()
{
    //Arrange
    Mock<ICheckCodeExist> checkCodeExist = new Mock<ICheckCodeExist>();
    checkCodeExist.Setup(x => x.IsCodeAvailable(50)).Returns(true);             
    var generateBrandNewCode = new GenerateBrandNewCode();
    var generateFromExistingCode = new GenerateFromExistingCode();
    var deliveryCode = new DeliveryCodeValue();

    var codeGeneratorController = new 
    CodeGeneratorController(checkCodeExist.Object, generateBrandNewCode, 
    generateFromExistingCode, deliveryCode);

    //Act
    IHttpActionResult actionResult = codeGeneratorController.Get(50);            
    var contentResult = actionResult as OkNegotiatedContentResult<DeliveryCodeValue>;

    //Assert
    Assert.IsNotNull(contentResult);
    Assert.IsNotNull(contentResult.Content);
    Assert.AreEqual("XYC456", contentResult.Content.Code);
}

Errors:

ContentNegotiator -
'((System.Web.Http.Results.OkNegotiatedContentResult)actionResult).ContentNegotiator' threw an exception of type 'System.InvalidOperationException' Formatters: '((System.Web.Http.Results.OkNegotiatedContentResult)actionResult).Formatters' threw an exception of type 'System.InvalidOperationException' Request: '((System.Web.Http.Results.OkNegotiatedContentResult)actionResult).Request' threw an exception of type 'System.InvalidOperationException'

Nkosi
  • 235,767
  • 35
  • 427
  • 472
Massey
  • 1,099
  • 3
  • 24
  • 50
  • Possible duplicate of [Why is this code throwing an InvalidOperationException?](https://stackoverflow.com/questions/16636374/why-is-this-code-throwing-an-invalidoperationexception) – Vijunav Vastivch Jan 07 '19 at 02:52
  • Before boxing 'actionResult' to 'OkNegotiatedContentResult', debug and check what the true type of 'actionResult' is. – Ashokan Sivapragasam Jan 07 '19 at 05:59

1 Answers1

0

You are casting to the wrong type in the test.

In the system under test you return

return Ok(_deliveryCode);

where _deliveryCode is

IDeliveryCode _deliveryCode;

thus the return type would be

OkNegotiatedContentResult<IDeliveryCode> //Interface

In the test you try to cast it to

OkNegotiatedContentResult<DeliveryCodeValue> //Concrete implementation

which would result in

var contentResult = actionResult as OkNegotiatedContentResult<DeliveryCodeValue>;

being null

Change the code to

var contentResult = actionResult as OkNegotiatedContentResult<IDeliveryCode>;

and it should behave as expected.

Finally, GenerateFromExistingCode.GetDeliveryCode returns "XYZ456", but the assertion is checking for "XYC456"

Assert.AreEqual("XYC456", contentResult.Content.Code);

Verify that that is indeed the desired assertion.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • Hi NKosi, I have changed the code to var contentResult = actionResult as OkNegotiatedContentResult; still contentResult comes as null. It should be "XYZ456". I have fixed it. – Massey Jan 07 '19 at 16:05
  • @Massey I misread the code, and copied the wrong interface. Check the updated answer. – Nkosi Jan 07 '19 at 16:10
  • Hi NKosi, I have changed my controller code to, return Created("", _couponCode); and the test code to var contentResult = actionResult as CreatedNegotiatedContentResult; Now it's working fine – Massey Jan 07 '19 at 18:08