0

I have this test class:

using NSubstitute;
using NUnit.Framework;
using System;
using System.Linq.Expressions;

namespace MyTests
{    
    public class Tests
    {
        [Test]
        public void Test()
        {
            var companyBL = Substitute.For<ICompanyBL>();

            companyBL.GetCompany(c => new { c.RegionID }).ReturnsForAnyArgs(new
            {
                RegionID = 4,
            });

            var company = companyBL.GetCompany(c => new { c.RegionID });

            var dataRetriever = new DataRetriever(companyBL);
        }
    }
}

and this code in another project:

namespace MyTests
{
    using System;
    using System.Linq.Expressions;

    public interface ICompanyBL
    {
        T GetCompany<T>(Expression<Func<Company, T>> selector);
    }

    public partial class Company
    {
        public int RegionID { get; set; }
    }

    public class DataRetriever
    {
        public DataRetriever(ICompanyBL companyBL)
        {
            //This is null:
            var company = companyBL.GetCompany(c => new
            {
                c.RegionID
            });
        }
    }
}

The company var is null. However, when the code is all contained in the same .cs file in the same project, the value is not null.

Why is the value null when used in another file in another project?

NSubstitute version = 1.10.0.0.

.NET Framework version = 4.5.2.

Issue submitted in Github: https://github.com/nsubstitute/NSubstitute/issues/598

David Klempfner
  • 8,700
  • 20
  • 73
  • 153
  • 1
    Custom mock for `ICompanyBL` should solve this issue, because it is not based on the type of passing arguments as NSubstitute does – Fabio Nov 20 '19 at 01:49

1 Answers1

2

I'm not sure how nsubstitute works but I believe you are running into issues where anonymous types only match inside single assembly, they are always different across assemblies.

Roughly you are mocking companyBL.GetCompany<TestAssembly.AnonymousTypeForRegionID> and your tested code calls companyBL.GetCompany<ProductAssembly.AnonymousTypeForRegionID>.

The easiest fix - use some type to pass data shared between those two assemblies. Even Tuple would do. More ideas in Return/consume dynamic anonymous type across assembly boundaries

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179