1

The return type of result and expected are different unable to fake an async method my code on x unit testing

using Amazon.Controllers;
using Amazon.Models;
using Amazon.Repository;
using FakeItEasy;
using FluentAssertions;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AmazonAPITest.Amazon_Controller_Merchant
{
    public  class Merchant_Controller_Test
    {
        private readonly IMerchantRepository _merchantRepository;

        public Merchant_Controller_Test()
        {
            _merchantRepository = A.Fake<IMerchantRepository>();
            
        }
        [Fact]
        public void MerchantController_GetMerchants_ListMerchantAsync()
        {
            //Arrange
            var MerchantList = A.Fake<Task<List<Merchant>>>();
            A.CallTo(() => _merchantRepository.GetMerchant()).Returns(MerchantList);
            var MerchantController = new MerchantController(_merchantRepository);
            var expected = A.Fake<Task<ActionResult<List<Merchant>>>>();

            //Act
            var result=  MerchantController.GetMerchants();
            
            //Assert
            result.Should().NotBeNull();
            result.Should().BeOfType<Task<ActionResult<List<Merchant>>>>();
           
            
        }
    }
}

controller action method code

[HttpGet]
    public async Task<ActionResult<List<Merchant>>> GetMerchants()
    {
        return await _repository.GetMerchant();
    }
    

repository code

  public async Task<List<Merchant>> GetMerchant()
    {
        try
        {
            return await _context.Merchants.ToListAsync();
        }
        catch
        {
            throw new NotImplementedException();

        }
    }

exception on debugging the test

Xunit.Sdk.XunitException: 'Expected type to be System.Threading.Tasks.Task1[[Microsoft.AspNetCore.Mvc.ActionResult1[[System.Collections.Generic.List1[[Amazon.Models.Merchant, AmazonAPI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], Microsoft.AspNetCore.Mvc.Core, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]]**, but found **System.Runtime.CompilerServices.AsyncTaskMethodBuilder1+AsyncStateMachineBox1[[Microsoft.AspNetCore.Mvc.ActionResult1[[System.Collections.Generic.List`1[[Amazon.Models.Merchant, AmazonAPI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], Microsoft.AspNetCore.Mvc.Core, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Runtime.CompilerServices.IAsyncStateMachine, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].

can someone figure any way to fake async method with fake it easy

Progman
  • 16,827
  • 6
  • 33
  • 48
akhil
  • 23
  • 4

1 Answers1

1

The problem isn't in faking the async method. It's how you've defined the return value:

var MerchantList = A.Fake<Task<List<Merchant>>>();

A fake Task<List<Merchant>> is not a Task<ActionResult<List<Merchant>>>.

When I replace your definition with

var MerchantList = new List<Merchant>();

(and supply a definition for MerchantController) the test passes. It's also easier to understand: an empty list is more familiar to the reader than a faked list. I'd recommend using concrete objects for your return values whenever possible.

(Also note that expected is unused in your example.)

My updated code, based on your expanded example:

// using Amazon.Controllers;
// using Amazon.Models;
// using Amazon.Repository;
using FakeItEasy;
using FluentAssertions;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AmazonAPITest.Amazon_Controller_Merchant
{
    public interface IMerchantRepository
    {
        Task<List<Merchant>> GetMerchant();
    }

    public class Merchant
    {
    }

    public class MerchantController
    {
        private readonly IMerchantRepository _repository;

        public MerchantController(IMerchantRepository repository) => _repository = repository;

        public async Task<ActionResult<List<Merchant>>> GetMerchants() => await _repository.GetMerchant();
    }


    public class Merchant_Controller_Test
    {
        private readonly IMerchantRepository _merchantRepository;

        public Merchant_Controller_Test()
        {
            _merchantRepository = A.Fake<IMerchantRepository>();

        }
        [Fact]
        public void MerchantController_GetMerchants_ListMerchantAsync()
        {
            //Arrange

            // THIS IS THE ONLY CHANGE I MADE TO THE TEST
            // var MerchantList = A.Fake<Task<List<Merchant>>>();
            var MerchantList = new List<Merchant>();

            A.CallTo(() => _merchantRepository.GetMerchant()).Returns(MerchantList);
            var MerchantController = new MerchantController(_merchantRepository);
            var expected = A.Fake<Task<ActionResult<List<Merchant>>>>();

            //Act
            var result = MerchantController.GetMerchants();

            //Assert
            result.Should().NotBeNull();
            result.Should().BeOfType<Task<ActionResult<List<Merchant>>>>();
        }
    }
}

Aside from this change, I would also ask you to consider why you're checking the type of the return value. It's a sort of weak condition, while also being brittle. A stronger and probably less fragile test might use the returned value to see if it has expected properties, such as the right contents. But perhaps you've simplified for reproduction benefits.

Blair Conrad
  • 233,004
  • 25
  • 132
  • 111
  • System.Runtime.CompilerServices.AsyncTaskMethodBuilder1+AsyncStateMachineBox1[[Microsoft.AspNetCore.Mvc.ActionResult1[[System.Collections.Generic.List`1[[Amazon.Models.Merchant, AmazonAPI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], Microsoft.AspNetCore.Mvc.Core, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],I am unable to match the return type when I made changes suggested by you – akhil Sep 08 '22 at 04:46
  • Ah, sorry. I will include all my code, as I should've to begin with. I had to guess at some pieces of your code, since you didn't include the `IMerchantRepository` definition and only the `MerchantController.GetMerchants` method, not the containing class. Please do so, to help get us to common ground. – Blair Conrad Sep 09 '22 at 10:15
  • Ok Blair Conrad – akhil Sep 09 '22 at 12:39
  • 'public async Task> GetMerchant() { try { return await _context.Merchants.ToListAsync(); } catch { throw new NotImplementedException(); } }' – akhil Sep 10 '22 at 06:33
  • github link : [https://github.com/Akhil1812007/AmazonAPI ] – akhil Sep 10 '22 at 06:37
  • I updated, taking your full test code and noting where I made changes. No difference for me: still passes. I cloned your repo as well, but there are no tests in there, so it didn't really help. – Blair Conrad Sep 10 '22 at 12:09
  • my test project is not getting loaded to github with the API project . i have no clues how to solve it . – akhil Sep 13 '22 at 05:03
  • You've not pushed any commits in which you have a test project. I'm willing to help you work through that, but this isn't the venue. If you'd like to meet me over at [the FakeItEasy gitter room](https://gitter.im/FakeItEasy/FakeItEasy), we can try to work it out. Do note, though, that I'm in UTC-4 and am going to be completely unavailable for my workdays for the rest of the week. – Blair Conrad Sep 13 '22 at 10:21
  • 1
    Thankyou @Blair Conrad the test case passed now with the correction you suggested earlier . – akhil Sep 14 '22 at 07:07
  • i have facing one more issue in unit testing [link]https://stackoverflow.com/questions/73726304/x-unit-testing-to-check-the-value-of-a-model-returned-by-an-async-method-in-asp – akhil Sep 15 '22 at 06:13