1

私のアプリでは、すべてのドメイン クラスが標準化に従っています。

  1. すべてがインターフェースを実装しますIEntity
  2. Idプロパティはprotected*
  3. 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ソートされます)OrdemCreateAt

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と それぞれのリポジトリが必要です。プロパティをモックできるように、すべてのオブジェクトは である必要があることを覚えておいてくださいPassoCheckListItensIEntityMock<>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<>、素晴らしい! しかし:

  1. それぞれPassoに 5 つの「モック」項目のリストがあり、それぞれが 1、2、3、4、5 Id(この順序で) である必要があります。これを達成する方法は?すでに入力されてIList<Mock<>>いる内部のこのリストを取得するにはどうすればよいですか? つまり構成は Mock<>Idpasso.SetupGet(x => x.CheckListItens).Returns( ???

  2. 私のコントローラーでオブジェクトを作成する責任者は、基本的に AutoMapper を使用して、私の ViewModel オブジェクトを永続化できるオブジェクトに変換 しmodel = Mapper.Map<TModel>(vm);
    ます。常に返すように AutoMapper を構成する方法は?IEntityMock<IEntity>Mock<>

4

1 に答える 1