私のアプリでは、すべてのドメイン クラスが標準化に従っています。
- すべてがインターフェースを実装します
IEntity
Id
プロパティはprotected
*- type のプロパティは
IList
、コンストラクターで保護および初期化されます。
以下は、ドメイン エンティティの典型的な例です。
public class CheckListItemTemplate : IEntity
{
public virtual int Id { get; protected set; }
public virtual string Text { get; set; }
public virtual CheckListItemTemplate Parent { get; set; }
public virtual IList<CheckListItemTemplate> Itens { get; protected set; }
public CheckListItemTemplate()
{
Itens = new List<CheckListItemTemplate>();
}
public void AddItem(CheckListItemTemplate item)
{
item.Parent = this;
Itens.Add(item);
}
}
*これは、ID がデータベースによって生成され、一部の開発者がこのプロパティを設定しようとするリスクを冒さないためです。
テスト プロジェクト
テストで使用される偽の汎用リポジトリがあります。
public class Repository<T> : IRepository<T>
where T : class, IEntity
{
private readonly IDictionary<int, T> _context = new Dictionary<int, T>();
public void Delete(T obj)
{
_context.Remove(obj.Id);
}
public void Store(T obj)
{
if (obj.Id > 0)
_context[obj.Id] = obj;
else
{
var generateId = _context.Values.Any() ? _context.Values.Max(p => p.Id) + 1 : 1;
var stub = Mock.Get<T>(obj);
stub.Setup(s => s.Id).Returns(generateId);
_context.Add(generateId, stub.Object);
}
}
// ..
}
* でわかるようにStore
、すべてのテスト オブジェクト (タイプIEntity
) はMock
** でなければなりません。これは、UI プロジェクトでは、オブジェクト NHibernate を保存するときにプロパティを更新するためId
です。プロジェクトのテストでは、これを手動で行う必要があり、プロパティId
に新しい値を設定する方法がないため、解決策はオブジェクト全体を新しい Id に対応するGet
プロパティにモックすることでした。Id
正確には、この行は何をしますかstub.Setup(s => s.Id).Returns(generateId)
。
*慣例により、ID <= 0 のオブジェクトは新規であり、ID> 0 はデータベース内の既存のオブジェクトです。
**モックにはMoqを使用します。
Id
保護されたまま
最大の問題は、Id
財産とそれがprotected
. デザイナーについて話すとき、これは優れたアプローチですが、アプリケーションをテストするときに非常に不便です。
たとえば、私が書いているテストでは、いくつかのデータが既に入力されている Fake リポジトリが必要です。
コード
フォローしてください。私は次のクラスを持っています(+CheckListItemTemplate
上に表示)。
public class Passo : IEntity
{
public int Id { get; protected set; }
public virtual IList<CheckListItemTemplate> CheckListItens { get; protected set; }
}
public class Processo : IEntity
{
public virtual int Id { get; protected set; }
public virtual Passo Passo { get; set; }
public virtual IList<CheckListItem> CheckListItens { get; protected set; }
}
を保存した後Processo
、最初Passo
のものが : に関連付けられます ( field に続くフィールドでProcesso
ソートされます)Ordem
CreateAt
model.Passo = PassoRepositorio.All().OrderBy(p => p.Ordem).ThenBy(p => p.CreateAt).First();
model.CheckListItens.Clear();
Parallel.ForEach(Mapper.Map<IList<CheckListItem>>(model.Passo.CheckListItens), (it) => model.AddCheckListItem(it));
このコードは、新しい を保存するたびに実行されますProcesso
。新しい を作成するテストではProcesso
、このコードが実行されます!
テスト
新しい. Processo
_ PassoRepositorio
_ Passos
_CheckListItemTemplates
*オブジェクトにダミー データを設定するには、 AutoFixtureを使用します。
**Passo
リポジトリに no が見つかり、.First()
チェックPasso
リストがない場合は失敗しますMapper.Map(model.Passo.CheckListItens)
。
したがって、 のリストを含むPassos
と それぞれのリポジトリが必要です。プロパティをモックできるように、すべてのオブジェクトは である必要があることを覚えておいてくださいPasso
CheckListItens
IEntity
Mock<>
Id
まずTestInitialize
、リポジトリにダミー データを入力するように設定します。
var fix = new Fixture();
var listPassos = fix.Build<Mock<Passo>>()
.Do((passo) => {
passo.SetupProperty(x => x.Nome, fix.Create<string>());
passo.SetupGet(x => x.CheckListItens).Returns(
fix.Build<CheckListItemTemplate>() // Needs to a Mock<>
.With(p => p.Texto)
.OmitAutoProperties()
.CreateMany(5).ToList()
);
})
.OmitAutoProperties()
.CreateMany(10);
foreach (var item in listPassos)
passoRepository.Store(item.Object);
次に、テストを実行できます。
[TestMethod]
public void Salvar_novo_processo_modificar_data_atendimento_passo_atual()
{
// Arrange
var fix = new Fixture();
var vm = fix.Create<ProcessoViewModel>();
//Act
Controller.salvar(vm); // Problem here. (For convert ProcessoViewModel to Processo I use a AutoMaper. In repository needs destination to be a Mock<Processo>
var processo = Repository.Get(p => p.DataEntrada == vm.DataEntrada && p.ProximoAtendimento == vm.ProximoAtendimento);
//Asserts
processo.Should().NotBeNull();
processo.Passo.Should().NotBeNull();
}
質問
10 個のリストを作成し、Passo
それぞれPasso
が実際にMock<>
、素晴らしい! しかし:
それぞれ
Passo
に 5 つの「モック」項目のリストがあり、それぞれが 1、2、3、4、5Id
(この順序で) である必要があります。これを達成する方法は?すでに入力されてIList<Mock<>>
いる内部のこのリストを取得するにはどうすればよいですか? つまり構成はMock<>
Id
passo.SetupGet(x => x.CheckListItens).Returns( ???
私のコントローラーでオブジェクトを作成する責任者は、基本的に AutoMapper を使用して、私の ViewModel オブジェクトを永続化できるオブジェクトに変換 し
model = Mapper.Map<TModel>(vm);
ます。常に返すように AutoMapper を構成する方法は?IEntity
Mock<IEntity>
Mock<>