複数の DbSet とその DbContext をモックしようとしています。私はこれについて困惑しています。フィードバックをいただければ幸いです。
テストを実行すると、次の null 参照例外が発生します。
System.NullReferenceException : オブジェクト参照がオブジェクトのインスタンスに設定されていません。
ここで、テスト メソッドで例外がスローされます。
return enterprisePubContext.WrWaterUsage
.Include(wu => wu.WaterUseCodeDescription)
.Include(wu => wu.PhysicalRight)
.ThenInclude(p => p.WaterRight)
.FirstOrDefault(wu => wu.PlaceOfUseId == placeOfUseId && wu.PhysicalRight.WaterRight != null);
ただし、テスト メソッドから結果を返すクエリに問題があるようには見えません。この問題は、各モック DbSet のセットアップ中に発生するようであり、モック DbSet のセットアップが失敗したため、その後モック DbContext のセットアップが失敗し、null コンテキストがテスト メソッドに渡されたように見えます。以前に DbSet に moq を使用したことがありますが、この問題に遭遇したことはありません。
テストをデバッグすると、DbSet ごとに次の例外が表示されますMock<IQueryable<entity>>.Setup<IQueryProvider>
(例mockPhysicalRights.As<IQueryable<WrPhysicalRight>>().Setup(m => m.Provider).Returns(physicalRights.Provider)
: )。
'((Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure)((Moq.Mock)(mockPhysicalRights)).Object).Instance' は、タイプ 'System.NotImplementedException' '((System.Linq.IQueryable)((Moq. Mock)(' mockDbSet ')).Object).Provider' は、タイプ 'System.NotImplementedException' '((Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure)((Moq.Mock)(mockPhysicalRights)).Object).Instance の例外をスローしました' 型 'System.NotImplementedException' '((System.Linq.IQueryable)((Moq.Mock)( mockDbSet)).Object).Expression' は、タイプ 'System.NotImplementedException' の例外をスローしました'System.NotImplementedException' '((System.Linq.IQueryable)((Moq.Mock)( mockDbSet )).Object).ElementType' がタイプ 'System.NotImplementedException' の例外をスローしました
デバッグ モードでの例外のスクリーンショットの例を次に示します。
スローされた同じ例外mockPhysicalRights.As<IQueryable<WrPhysicalRight>>().Setup(m => m.Provider).Returns(physicalRights.Provider)
が以下でもスローされます。
mockPhysicalRights.As<IQueryable<WrPhysicalRight>>()
.Setup(m => m.Expression).Returns(physicalRights.Expression);
'((System.Linq.IQueryable)((Moq.Mock)(mockPhysicalRights)).Object).Expression' がタイプ 'System.NotImplementedException' の例外をスローしました
mockPhysicalRights.As<IQueryable<WrPhysicalRight>>()
.Setup(m => m.ElementType).Returns(physicalRights.ElementType);
'((System.Linq.IQueryable)((Moq.Mock)(mockPhysicalRights)).Object).ElementType' がタイプ 'System.NotImplementedException' の例外をスローしました
DbContext を設定するときは、
var mockEnterprisePubContext = new Mock<EnterprisePubContext>();
mockEnterprisePubContext.Setup(m => m.WrPhysicalRight)
.Returns(mockPhysicalRights.Object);
次のエラーが表示されます。
エラー CS0103: 名前 'm' は現在のコンテキストに存在しません
これはデバッグモードのスクリーンショットです。
うまくいけば、以下に関連するすべてのコードが含まれています。
DbContext - 簡単にするために、関係のないコードは省略されていると想定
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 - 簡単にするために、関係のないコードは省略されていると想定
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; }
}
テスト方法 - 簡単にするために無関係なコードは省略されていると想定
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);
}
}
}
テスト
/// <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);
}