1

私はここで困惑しています。私は、こことNSubstituteのドキュメントの両方で、私の質問に対する実行可能な答えを見つけるのに苦労しました。

オブジェクトがリポジトリに追加された後、そのオブジェクトのナビゲーションプロパティにアクセスして他の作業を行う、サービスメソッドの単体テストを試みています。単体テストがコード内で新しいオブジェクトのナビゲーションプロパティにアクセスするポイントに到達すると、NullReferenceExceptionが発生します。モックで何を返すかを教えていないので、なぜ例外が発生するのかはわかりますが、ナビゲーションプロパティにアクセスするときにユニットテストに何を返すかをユニットテストに伝える方法がわかりません。これはすべて、オブジェクトが実行時に作成されるためです。

簡潔にするために、関連するメソッドの部分のみを含めます。

// This is the method I am trying to unit test
public void SaveSelectedResultsMeasures(SelectResultsMeasuresViewModel model)
{
    // validate the model
    ...

    var cpf = this.repository.GetCareerPlanningFormByID(model.CareerPlanningFormID);

    model.ResultsMeasuresSections.ToList().ForEach(resultsMeasuresSection =>
    {
        var selectedResultsMeasuresSection = cpf.SelectedResultsMeasuresSections
                                                .Where(o => o.ResultsMeasuresSectionID == resultsMeasuresSection.SectionID)
                                                .ToMaybe();

        if (resultsMeasuresSection.IsSelected)
        {
            if (!selectedResultsMeasuresSection.HasValue)
            {
                // here is where the new object is being created and added to the repository
                cpf.SelectedResultsMeasuresSections.Add(new SelectedResultsMeasuresSection
                {
                    CareerPlanningFormID = cpf.CareerPlanningFormID,
                    IsDeleted = false,
                    ResultsMeasuresSectionID = resultsMeasuresSection.SectionID,
                    RepeatNumberOfOccurrences = resultsMeasuresSection.RepeatNumberOfOccurrences ?? 1
                });
                this.repository.Commit();

                // now that the add has been committed, i get the object i just created
                var newSelectedResultsMeasuresSection = cpf.SelectedResultsMeasuresSections
                    .Where(o => o.ResultsMeasuresSectionID == resultsMeasuresSection.SectionID)
                    .Single();

                // here is where i access the navigation properties of that object
                // this works just fine, just need to figure out how to unit test it so that i can continue to test the code inside the block
                // when the unit test hits this point, this is where I get the NullReferenceException
                newSelectedResultsMeasuresSection.ResultsMeasuresSection.ResultsMeasures.ToList().ForEach(rm =>
                {
                    // code here...
                }
            }
        }
    }
}

// This is the unit test
[TestClass]
[ExcludeFromCodeCoverage]
public class CareerPlanningFormServiceTest
{
    private readonly IPartnerPerformanceManagementConfiguration configuration;
    private readonly IPartnerPerformanceManagementRepository repository;
    private readonly IPrincipal currentUser;
    private readonly CareerPlanningFormService target;

    public CareerPlanningFormServiceTest()
    {
        this.configuration = Substitute.For<IPartnerPerformanceManagementConfiguration>();
        this.repository = Substitute.For<IPartnerPerformanceManagementRepository>();
        this.currentUser = Substitute.For<IPrincipal>();

        this.target = new CareerPlanningFormService(
            this.configuration,
            this.repository,
            this.currentUser);
    }

    /// <summary>
    /// Tests the SaveSelectedResultsMeasures method.
    /// Test success when adding a new SelectedResultsMeasuresSection
    /// </summary>
    [TestMethod]
    [TestCategory("CareerPlanningFormService")]
    [TestCategory("CareerPlanningFormService - SaveSelectedResultsMeasures")]
    public void SaveSelectedResultsMeasures_Test_Success_Add_SelectedResultsMeasuresSection()
    {
        // Arrange
        var model = new SelectResultsMeasuresViewModel
        {
            CareerPlanningFormID = 1,
            ResultsMeasuresSections = new List<ResultsMeasuresSectionModel>
            {
                new ResultsMeasuresSectionModel
                {
                    SectionID = 1,
                    IsRequired = false,
                    IsSelected = true,
                    ActionPlanLabels = new List<ActionPlanLabelModel>
                    {
                        new ActionPlanLabelModel
                        {
                            LabelID = 1,
                            IsSelected = true,
                        }
                    },
                    CanRepeat = false
                },
                new ResultsMeasuresSectionModel
                {
                    SectionID = 2,
                    IsRequired = false,
                    IsSelected = true,
                    ActionPlanLabels = new List<ActionPlanLabelModel>(),
                    CanRepeat = true,
                    RepeatNumberOfOccurrences = 2
                }
            }
        };
        var cpf = new CareerPlanningForm
        {
            CareerPlanningFormID = 1,
            SelectedResultsMeasuresSections = new EntitySet<SelectedResultsMeasuresSection>()
        };
        this.repository.GetCareerPlanningFormByID(model.CareerPlanningFormID).Returns(cpf);

        // Act
        this.target.SaveSelectedResultsMeasures(model);

        // Assert
        this.repository.Received(8).Commit();
        Assert.AreEqual(2, cpf.SelectedResultsMeasuresSections.Count);

        Assert.AreEqual(1, cpf.SelectedResultsMeasuresSections.Where(o => o.ResultsMeasuresSectionID == 1).Single().SelectedActionPlanLabels.Count());
        Assert.AreEqual(1, cpf.SelectedResultsMeasuresSections.Where(o => o.ResultsMeasuresSectionID == 1).Single().ResultsMeasuresSectionOccurrences.Count());

        Assert.AreEqual(0, cpf.SelectedResultsMeasuresSections.Where(o => o.ResultsMeasuresSectionID == 2).Single().SelectedActionPlanLabels.Count());
        Assert.AreEqual(2, cpf.SelectedResultsMeasuresSections.Where(o => o.ResultsMeasuresSectionID == 2).Single().ResultsMeasuresSectionOccurrences.Count());
    }
}

他に役立つことがあれば、教えてください。

4

1 に答える 1

0

テストで戻ってきたものに追加する必要があるようですResultsMeasuresResultsMeasuresSections

ただし、そのパスをさらに進める前に、LINQ-to-SQLの動作をシミュレートするために多くの作業を行っているようです。コードの動作の特定のメカニズムをテストする単体テストを削除し、実際のデータベースまたはインメモリデータベースにヒットするテストに切り替えて、コードが目的の動作をすることを確認することをお勧めします。たとえば、CPFの結果測定値を保存した場合、CPFに必要な情報が含まれていることを確認してください。

次のようなテストの欠点.Received(8).Commit()は、コードが実際に必要に応じて動作しているかどうかではなく、他のシステムがどのように動作するかを知っている/期待していることに対してテストしていることです。テストするときに私たちにとって最も価値があるのは後者の点だと思います。

于 2012-12-09T22:46:58.733 に答える