2

I am attempting to mock multiple DbSets and their DbContext. I'm stumped about this one. I appreciate any feedback.

When I run the test, I receive the following null reference exception:

System.NullReferenceException : Object reference not set to an instance of an object.

The exception is thrown here in the test method:

return enterprisePubContext.WrWaterUsage
    .Include(wu => wu.WaterUseCodeDescription)
    .Include(wu => wu.PhysicalRight)
        .ThenInclude(p => p.WaterRight)
    .FirstOrDefault(wu => wu.PlaceOfUseId == placeOfUseId && wu.PhysicalRight.WaterRight != null);

However, it does not seem as if the problem is with the query which returns a result from the test method. The problem appears to occur during setup for each mock DbSet, and since setup for mock DbSets fails, then set up for the mock DbContext subsequently fails, and it seems as if a null context is passed to the test method. I have used moq for DbSets before and never encountered this problem.

When I debug the test, I see the following exception for each DbSet and for each Mock<IQueryable<entity>>.Setup<IQueryProvider>(for example, mockPhysicalRights.As<IQueryable<WrPhysicalRight>>().Setup(m => m.Provider).Returns(physicalRights.Provider)):

'((Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure)((Moq.Mock)(mockPhysicalRights)).Object).Instance' threw an exception of type 'System.NotImplementedException' '((System.Linq.IQueryable)((Moq.Mock)('mockDbSet')).Object).Provider' threw an exception of type 'System.NotImplementedException' '((Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure)((Moq.Mock)(mockPhysicalRights)).Object).Instance' threw an exception of type 'System.NotImplementedException' '((System.Linq.IQueryable)((Moq.Mock)(mockDbSet)).Object).Expression' threw an exception of type 'System.NotImplementedException' '((Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure)((Moq.Mock)(mockPhysicalRights)).Object).Instance' threw an exception of type 'System.NotImplementedException' '((System.Linq.IQueryable)((Moq.Mock)(mockDbSet)).Object).ElementType' threw an exception of type 'System.NotImplementedException'

Here are screenshot examples of the exceptions in debug mode:

((Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<System.IServiceProvider>)((Moq.Mock)(mockPhysicalRights)).Object).Instance' threw an exception of type 'System.NotImplementedException

'((System.Linq.IQueryable)((Moq.Mock)(mockPhysicalRights)).Object).Provider' threw an exception of type 'System.NotImplementedException'

The same exception thrown on mockPhysicalRights.As<IQueryable<WrPhysicalRight>>().Setup(m => m.Provider).Returns(physicalRights.Provider) is also thrown on:

mockPhysicalRights.As<IQueryable<WrPhysicalRight>>()
    .Setup(m => m.Expression).Returns(physicalRights.Expression);

'((System.Linq.IQueryable)((Moq.Mock)(mockPhysicalRights)).Object).Expression' threw an exception of type 'System.NotImplementedException'

mockPhysicalRights.As<IQueryable<WrPhysicalRight>>()
    .Setup(m => m.ElementType).Returns(physicalRights.ElementType);

'((System.Linq.IQueryable)((Moq.Mock)(mockPhysicalRights)).Object).ElementType' threw an exception of type 'System.NotImplementedException'

When setting up the DbContext,

var mockEnterprisePubContext = new Mock<EnterprisePubContext>();
mockEnterprisePubContext.Setup(m => m.WrPhysicalRight)
    .Returns(mockPhysicalRights.Object);

I see the following error:

error CS0103: The name 'm' does not exist in the current context

Here is a screenshot in debug mode.

error CS0103: The name 'm' does not exist in the current context

Hopefully, I have included all the relevant code below.

DbContext - assumed irrelevant code is omitted for simplicity

public class EnterprisePubContext : DbContext
{
    public EnterprisePubContext()
    {
    }
    public EnterprisePubContext(DbContextOptions<EnterprisePubContext> options) : base(options)
    {
    }
    public virtual DbSet<WrPhysicalRight> WrPhysicalRight { get; set; }
    public virtual DbSet<WrWaterUsage> WrWaterUsage { get; set; }
    public virtual DbSet<WrWaterUseCode> WrWaterUseCode { get; set; }
    public virtual DbSet<WrWaterRight> WrWaterRight { get; set; }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<WrPhysicalRight>(entity =>
        {
             entity.HasKey(e => e.RightId)
                 .HasName("wrPhysicalRightPK")
                 .IsClustered(false);
             entity.ToTable("wrPhysicalRight", "dbo");
             entity.Property(e => e.RightId).HasColumnName("RightID");
             entity.HasOne<WrWaterRight>(pr => pr.WaterRight)
                 .WithOne(wr => wr.PhysicalRight)
                 .HasForeignKey<WrWaterRight>(wr => wr.RightId);  
        });
        modelBuilder.Entity<WrWaterRight>(entity =>
        {
            entity.HasKey(e => new { e.BasinNumber, e.SequenceNumber, e.SplitSuffix })
                .HasName("wrWaterRightPK")
                .IsClustered(false);
            entity.ToTable("wrWaterRight", "dbo");
            entity.Property(e => e.SplitSuffix)
                .HasMaxLength(2)
                .IsUnicode(false);
            entity.Property(e => e.Basis)
                .HasMaxLength(100)
                .IsUnicode(false);   
            entity.Property(e => e.RightId).HasColumnName("RightID");
            entity.Property(e => e.Status)
                .HasMaxLength(100)
                .IsUnicode(false);
        });
        modelBuilder.Entity<WrWaterUsage>(entity =>
        {
            entity.HasKey(e => new { e.WaterUseCode, e.RightId })
                .HasName("wrWaterUsagePK")
                .IsClustered(false);
            entity.ToTable("wrWaterUsage", "dbo");
            entity.Property(e => e.WaterUseCode)
                .HasMaxLength(2)
                .IsUnicode(false);
            entity.Property(e => e.RightId).HasColumnName("RightID");
            entity.Property(e => e.LargePou).HasColumnName("LargePOU");
            entity.Property(e => e.PlaceOfUseId).HasColumnName("PlaceOfUseID");
            entity.HasOne<WrPhysicalRight>(usage => usage.PhysicalRight)
                .WithMany(pr => pr.WaterUsages)
                .HasForeignKey(usage => usage.RightId)
                .IsRequired();
            entity.HasOne<WrWaterUseCode>(usage => usage.WaterUseCodeDescription)
                .WithMany(code => code.Usages)
                .HasForeignKey(usage => usage.WaterUseCode)
                .IsRequired();
        });
        modelBuilder.Entity<WrWaterUseCode>(entity =>
        {
            entity.HasKey(e => e.WaterUseCode)
               .HasName("wrWaterUseCodePK")
               .IsClustered(false);
            entity.ToTable("wrWaterUseCode", "dbo");
            entity.Property(e => e.WaterUseCode)
               .HasMaxLength(2)
               .IsUnicode(false)
               .ValueGeneratedNever();
            entity.Property(e => e.Description)
               .HasMaxLength(255)
                 .IsUnicode(false);
        });
    }
}

DbSets - assumed irrelevant code is omitted for simplicity

public class WrPhysicalRight
{
     [Key]
     public int RightId { get; set; }
     [ForeignKey("RightId")]
     public IList<WrWaterUsage> WaterUsages { get; set; }
     public WrWaterRight WaterRight { get; set; }
}
public class WrWaterUsage
{
    public string WaterUseCode { get; set; }
    public int RightId { get; set; }
    public int? PlaceOfUseId { get; set; }
    public double? TotalAcres { get; set; }
    public double? AcreLimit { get; set; }
    public bool LargePou { get; set; }
    public WrPhysicalRight PhysicalRight { get; set; }
    public WrWaterUseCode WaterUseCodeDescription { get; set; }
}
public class WrWaterUseCode
{
    public string WaterUseCode { get; set; }
    public string Description { get; set; }
    [ForeignKey("WaterUseCode")]
    public IList<WrWaterUsage> Usages { get; set; }
}
public class WrWaterRight
{
    [Key]
    public int BasinNumber { get; set; }
    [Key]
    public int SequenceNumber { get; set; }
    [Key]
    public string SplitSuffix { get; set; }
    public int? RightId { get; set; }
    public string Status { get; set; }
    public string Basis { get; set; }
    [ForeignKey("RightId")]
    public WrPhysicalRight PhysicalRight { get; set; }
}

Test methods - assumed irrelevant code is omitted for simplicity

public abstract class Process : Enumeration<string>
{
    protected readonly List<string> Aliases = new List<string>();
    private Process(int value, string displayName, IEnumerable<string> aliases) : base(value, 
        displayName)
    {
        Aliases.Add(displayName);
        Aliases.AddRange(aliases);
    }
    public static readonly Process WaterRight = new WaterRightProcess();

    public static WrWaterUsage WaterUsageByPlaceOfUseId(EnterprisePubContext enterprisePubContext,
        int placeOfUseId, ref Process process)
    {
        if (process != null)
            return process.GetWaterUsageByPlaceOfUseId(enterprisePubContext, placeOfUseId);
        return null;
    }

    private class WaterRightProcess : Process
    {
        internal WaterRightProcess() : base(0, "WaterRight", new [] { "right" })
        {
        }
        protected override WrWaterUsage GetWaterUsageByPlaceOfUseId(EnterprisePubContext 
            enterprisePubContext, int placeOfUseId)
        {
            //Exception thrown here
            return enterprisePubContext.WrWaterUsage
                .Include(wu => wu.WaterUseCodeDescription)
                .Include(wu => wu.PhysicalRight)
                    .ThenInclude(p => p.WaterRight)
                .FirstOrDefault(wu => wu.PlaceOfUseId == placeOfUseId && wu.PhysicalRight.WaterRight 
                    != null);
        }
    }
}

Test

/// <summary>
/// Ensure that water right process returns PlaceOfUse by PlaceOfUseId appropriately 
/// </summary>
[Fact]
public void WaterRightProcessReturnsWaterUsageByPlaceOfUseWithMocking()
{
    //Mocking physical rights entity
    var physicalRights = new List<WrPhysicalRight>
    {
        new WrPhysicalRight
        {
            RightId = 1
        }
    }.AsQueryable();
    var mockPhysicalRights = new Mock<DbSet<WrPhysicalRight>>();
    mockPhysicalRights.As<IQueryable<WrPhysicalRight>>()
        .Setup(m => m.Provider).Returns(physicalRights.Provider);
    mockPhysicalRights.As<IQueryable<WrPhysicalRight>>()
        .Setup(m => m.Expression).Returns(physicalRights.Expression);
    mockPhysicalRights.As<IQueryable<WrPhysicalRight>>()
        .Setup(m => m.ElementType).Returns(physicalRights.ElementType);
    mockPhysicalRights.As<IQueryable<WrPhysicalRight>>()
        .Setup(m => m.GetEnumerator()).Returns(physicalRights.GetEnumerator());

    //Mocking water usages entity
    var waterUsages = new List<WrWaterUsage>
    {
        new WrWaterUsage
        {
            RightId = 1,
            WaterUseCode = "01",
            PlaceOfUseId = 1,
            AcreLimit = 12,
            TotalAcres = 12,
            LargePou = false
        }
    }.AsQueryable();
    var mockWaterUsages = new Mock<DbSet<WrWaterUsage>>();
    mockWaterUsages.As<IQueryable<WrWaterUsage>>()
        .Setup(m => m.Provider).Returns(waterUsages.Provider);
    mockWaterUsages.As<IQueryable<WrWaterUsage>>()
        .Setup(m => m.Expression).Returns(waterUsages.Expression);
    mockWaterUsages.As<IQueryable<WrWaterUsage>>()
        .Setup(m => m.ElementType).Returns(waterUsages.ElementType);
    mockWaterUsages.As<IQueryable<WrWaterUsage>>()
        .Setup(m => m.GetEnumerator()).Returns(waterUsages.GetEnumerator());

    //Mocking water use codes entity
    var waterUseCodes = new List<WrWaterUseCode>
    {
        new WrWaterUseCode
        {
            WaterUseCode = "01",
            Description = "IRRIGATION"
        }
    }.AsQueryable();
    var mockWaterUseCodes = new Mock<DbSet<WrWaterUseCode>>();
    mockWaterUseCodes.As<IQueryable<WrWaterUseCode>>()
        .Setup(m => m.Provider).Returns(waterUseCodes.Provider);
    mockWaterUseCodes.As<IQueryable<WrWaterUseCode>>()
        .Setup(m => m.Expression).Returns(waterUseCodes.Expression);
    mockWaterUseCodes.As<IQueryable<WrWaterUseCode>>()
        .Setup(m => m.ElementType).Returns(waterUseCodes.ElementType);
    mockWaterUseCodes.As<IQueryable<WrWaterUseCode>>()
        .Setup(m => m.GetEnumerator()).Returns(waterUseCodes.GetEnumerator());

    //Mocking water rights entity
    var waterRights = new List<WrWaterRight>
    {
        new WrWaterRight
        {
            RightId = 1,
            BasinNumber = 63
            SequenceNumber = 9874,
            SplitSuffix = "",
            Status = "Active",
            Basis = "Statutory Claim"
        }
    }.AsQueryable();
    var mockWaterRights = new Mock<DbSet<WrWaterRight>>();
    mockWaterRights.As<IQueryable<WrWaterRight>>()
        .Setup(m => m.Provider).Returns(waterRights.Provider);
    mockWaterRights.As<IQueryable<WrWaterRight>>()
        .Setup(m => m.Expression).Returns(waterRights.Expression);          
    mockWaterRights.As<IQueryable<WrWaterRight>>()
        .Setup(m => m.ElementType).Returns(waterRights.ElementType);
    mockWaterRights.As<IQueryable<WrWaterRight>>()
        .Setup(m => m.GetEnumerator()).Returns(waterRights.GetEnumerator());

    //Mocking EnterprisePubContext
    var mockEnterprisePubContext = new Mock<EnterprisePubContext>();
    mockEnterprisePubContext.Setup(m => m.WrPhysicalRight)
        .Returns(mockPhysicalRights.Object);
    mockEnterprisePubContext.Setup(m => m.WrWaterUsage)
        .Returns(mockWaterUsages.Object);
    mockEnterprisePubContext.Setup(m => m.WrWaterUseCode)
       .Returns(mockWaterUseCodes.Object);
    mockEnterprisePubContext.Setup(m => m.WrWaterRight)
        .Returns(mockWaterRights.Object);

    Process process = Process.WaterRight;

    var waterUsage = Process.WaterUsageByPlaceOfUseId(mockEnterprisePubContext.Object, 1, ref 
        process);

    Assert.Equal("01", waterUsage.WaterUseCode);
}
Thor
  • 181
  • 1
  • 2
  • 8

1 Answers1

0

After arranging my thoughts in the above post, it struck me that mocking DbSets might not work like creating InMemoryDatabases. Before trying to mock test the method, I created an InMemoryDatabase to test the same method, and this is the code for creating the InMemoryDatabase which was successfully used to test the method.

var options= new DbContextOptionsBuilder<EnterprisePubContext>()
    .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
    .EnableSensitiveDataLogging()
    .Options;
var databaseContext = new EnterprisePubContext(options);
databaseContext.Database.EnsureCreated();

if (!databaseContext.WrPhysicalRight.Any())
{
    databaseContext.WrPhysicalRight.Add(new WrPhysicalRight()
    {
        RightId = 1
    });
}
if (!databaseContext.WrWaterUsage.Any())
{
    databaseContext.WrWaterUsage.Add(new WrWaterUsage()
    {
        RightId = 1,
        WaterUseCode = "01",
        PlaceOfUseId = 1,
        AcreLimit = 12,
        TotalAcres = 12,
        LargePou = false
    });
 }
if (!databaseContext.WrWaterUseCode.Any())
{
    databaseContext.WrWaterUseCode.Add(new WrWaterUseCode()
    {
        WaterUseCode = "01",
        Description = "IRRIGATION"
    });
}
if (!databaseContext.WrWaterRight.Any())
{
    databaseContext.WrWaterRight.Add(new WrWaterRight()
    {
        RightId = 1,
        BasinNumber = 63,
        SequenceNumber = 9874,
        SplitSuffix = "",
        Status = "Active",
        Basis = "Statutory Claim"
    });
}

This entity initialization worked fine for creating an InMemoryDatabase. Apparently, the InMemoryDatabase implicitly forms relationships. Moq does not implicitly form relationships when mocking DbSets. I had to initialize the relational properties to make the mock DbSets work.

//Mocking physical rights entity
var physicalRights = new List<WrPhysicalRight>
{
    new WrPhysicalRight
    {
        RightId = 1,
        WaterRight = new WrWaterRight
        {
            RightId = 1,
            BasinNumber = 63,
            SequenceNumber = 9874,
            SplitSuffix = "",
            Status = "Active",
            Basis = "Statutory Claim"
        }
    }
}.AsQueryable();

//Mocking water usages entity
var waterUsages = new List<WrWaterUsage>
{
    new WrWaterUsage
    {
        RightId = 1,
        WaterUseCode = "01",
        PlaceOfUseId = 1,
        AcreLimit = 12,
        TotalAcres = 12,
        LargePou = false,
        PhysicalRight = new WrPhysicalRight
        {
            RightId = 1,
            WaterRight = new WrWaterRight
            {
                RightId = 1,
                BasinNumber = 63,
                SequenceNumber = 9874,
                SplitSuffix = "",
                Status = "Active",
                Basis = "Statutory Claim"
            }
        },
        WaterUseCodeDescription = new WrWaterUseCode
        {
            WaterUseCode = "01",
            Description = "IRRIGATION"
        }
    }
}.AsQueryable();

//Mocking water use codes entity
var waterUseCodes = new List<WrWaterUseCode>
{
    new WrWaterUseCode
    {
        WaterUseCode = "01",
        Description = "IRRIGATION",
        Usages = new List<WrWaterUsage>
        {
            new WrWaterUsage
            {
                RightId = 1,
                WaterUseCode = "01",
                PlaceOfUseId = 1,
                AcreLimit = 12,
                TotalAcres = 12,
                LargePou = false,
                PhysicalRight = new WrPhysicalRight
                {
                    RightId = 1,
                    WaterRight = new WrWaterRight
                    {
                        RightId = 1,
                        BasinNumber = 63,
                        SequenceNumber = 9874,
                        SplitSuffix = "",
                        Status = "Active",
                        Basis = "Statutory Claim"
                    }
                },
                WaterUseCodeDescription = new WrWaterUseCode
                {
                    WaterUseCode = "01",
                    Description = "IRRIGATION"
                }
            }
        }
    }
}.AsQueryable();

//Mocking water rights entity
var waterRights = new List<WrWaterRight>
{
    new WrWaterRight
    {
        RightId = 1,
        BasinNumber = 63,
        SequenceNumber = 9874,
        SplitSuffix = "",
        Status = "Active",
        Basis = "Statutory Claim",
        PhysicalRight = new WrPhysicalRight
        {
            RightId = 1,
            WaterRight = new WrWaterRight
            {
                RightId = 1,
                BasinNumber = 63,
                SequenceNumber = 9874,
                SplitSuffix = "",
                Status = "Active",
                Basis = "Statutory Claim"
            }
        }
    }
}.AsQueryable();

Explicitly relating physical rights with water rights, water usages with physical rights and water use codes, water use codes with water usages, and water rights with physical rights was necessary to properly create the mock context which the method uses to query all those mock DbSets. Not sure about the difference in what is happening behind the scenes with mocking vs. InMemoryDatabases, but explicit creation of relationships with mocking is REQUIRED.

Thor
  • 181
  • 1
  • 2
  • 8