34
39

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Moqを使ってEntityframeworkのモックを作成するには?【単体テスト】

Last updated at Posted at 2016-01-20

C#の単体テスト用モックフレームワークといえば、Moqがデフォルトですが、Entityframeworkとの相性があまりよくありませんでした。

DbContextのモック実装を用意したり、実コードと差し替えるためにインターフェースを作成する必要があるので、モックの規模が膨らみ、クラス設計にも影響します。

とは言え、単体テストフェーズでJavaのDBUnitのようなDBにデータを仕込むアプローチを取ると、テストデータが膨大になったり、仕様変更、リファクタリングのコストが大きくなってしまいます。

Entityframework6以降では、モック用のインターフェースやダミーを作成せずに、単体テストが組めるようになりました。

DbContextの変更

public class MyDbContext : DbContext
{
     // Mockに差し替えるEntityはvirtualにしてオーバーライド可能に
     public virtual DbSet<MyEntity> MyEntitys { get; set; }
}

モックの設定(SetUp)

// Mock用のデータ
var dataEntity = new List<MyEntity>
{
    new MyEntity {Id = 1, Date = Datetime.Now },
    new MyEntity {Id = 2, Date = Datetime.Now }
}.AsQueryable();

// DbSetのMock
var mockMyEntity = new Mock<DbSet<MyEntity>>();
// DbSetとテスト用データを紐付け
mockMyEntity.As<IQueryable<Type>>().Setup(m => m.Provider).Returns(dataEntity.Provider);
mockMyEntity.As<IQueryable<Type>>().Setup(m => m.Expression).Returns(dataEntity.Expression);
mockMyEntity.As<IQueryable<Type>>().Setup(m => m.ElementType).Returns(dataEntity.ElementType);
mockMyEntity.As<IQueryable<Type>>().Setup(m => m.GetEnumerator()).Returns(dataEntity.GetEnumerator());

// DBContextにMockを設定
var mockContext = new Mock<<MyDbContext>();
mockContext.Setup(m => m.TestEntity).Returns(mockMyEntity.Object);
mockMyEntity.SetUp(f => f.Create()).Returns(new MyEntity());

// DBContextのMockをコンストラクタなどからテスト対象クラスに受け渡す
var target = new Target(mockContext);

エンティティの関連を使っている場合、自動では設定されないので、自力で設定する必要があります。

参照系のテスト

// Mockに設定したデータが取得できる
Assert.AreEqual(1, target.List(1).Id);

更新系のテスト

var ret = target.Save("xyz");
// Addが一回呼び出されること
mockMyEntity.Verify(m => m.Add(It.IsAny<MyEntity>()), Times.Once);
// 想定通りのエンティティが作成されていること
mockMyEntity.Verify(m => m.Add(It.Is<MyEntity>(t => t.Id.Equals(1))));

単体テストはそれなりに手間がかかりますが、仕様変更やリファクタリングがあっても心の平安が保てますし、デグレもないので結果的に早いです。

追記

MSDNでSQL LiteやLocalDBのInMemory Modeや使ったテスト方法が紹介されていました。
クエリのテストする場合、こちらの方がMoqに慣れていない人には分かりやすいかもしれません。

34
39
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
39

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?