CmsContentScaffolding パッケージを使用した単体テストの最適化

1714127654
2024-04-26 09:49:47

単体テストは、ビジネス ロジックのためだけでなく、コンテンツやコンテンツ作成用に定義されたルール (利用可能なコンテンツ タイプ、検証など) についても作成する必要があります。 そうすることで、Optimizely ソリューションはコンテンツ タイプやルールの変更に対する復元力が高まります。

通常、継続的に使用されるローカル開発 DB またはテスト DB があり、テスト コンテンツは Optimizely で作成され、バックエンド開発ではコンテンツ タイプと検証ルールが継続的に変更されるため、コンテンツが最初から作成されたかのように検証されることはほとんどありません。 そのため、テスト コンテンツがクライアントが作成できる現実的なイメージを表しているという誤った考えにつながる可能性がありますが、クライアントがコンテンツの作成を開始するとすぐに、ステージング環境でこれらの問題が発生し始めます。

コンテンツ単体テストで得られる利点は、変更が導入されるとすぐに目的のサイト構造と検証ルールを検証し、常に空の DB から最初から開始し、コントローラー出力モデルに必要なデータがすべて含まれていることを検証することです。 コンテンツ構造の概要を簡単に説明するために、単純な流暢な構文を使用する CmsContentScaffolding というライブラリがあります。 完全なサイト構造を作成し、大量のページを簡単に作成し、テスト用のコンテンツを準備できます。

Nuget パッケージとして追加され、以下を使用してサービスの依存関係が登録されました。 services.AddCmsContentScaffolding();、続いて Iアプリケーションビルダー 拡張メソッド appBuilder.UseCmsContentScaffolding(builderOptions: o => {}, builder: b => {});。 次の 2 つのセクションがあります。 ビルダーオプション (使用言語、サイトホスト、サイト名、ページドラフトの公開または作成のみ、ユーザーとロールなどのグローバルオプションを提供します…) ビルダー コンテンツ作成のメソッドを公開します。 の別のセクションを使用して、複数のサイトを作成できます。 appBuilder.UseCmsContentScaffolding(builderOptions: o => {}, builder: b => {});。 Builder には、コンテンツの作成を開始する開始点として機能する UseAssets(ContentReference.SiteBlockFolder) と UsePages(ContentReference.RootPage) の 2 つの主要なメソッドがあります。

さらに、CmsContentScaffolding.Shared.Resources と呼ばれる、偽のテキスト、画像、ビデオ用のヘルパー メソッドを備えたパッケージもあります。

UseCmsContentScaffolding メソッドには多くのオプションがあり、次のようになります。

app.UseCmsContentScaffolding(
    builderOptions: o =>
    {
        o.Language = CultureInfo.GetCultureInfo("sr");
        o.StartPageType = typeof(StartPage);
        o.BuildMode = BuildMode.Append;
    },
    builder: b =>
    {
        var teaser2Ref = ContentReference.EmptyReference;
        var teaser3Ref = ContentReference.EmptyReference;
        var articlePageRef = ContentReference.EmptyReference;

        b.UseAssets(ContentReference.SiteBlockFolder)
        .WithFolder("Folder 1", l1 =>
        {
            l1
            .WithFolder("Folder 1_1", l2 =>
            {
                l2.WithBlock("Teaser 1", out teaser2Ref, x =>
                {
                    x.Heading = "Teaser 1 Heading";
                    x.Text = ResourceHelpers.Faker.Lorem.Paragraph();
                    x.Image = PropertyHelpers.GetOrAddMedia("Image 2", ".png", ResourceHelpers.GetImageStream());
                });
            })
            .WithMedia(x => x.Name = "Test video", ResourceHelpers.GetVideoStream(), ".mp4")
            .WithBlock("Teaser 3", out teaser3Ref, x =>
            {
                x.Heading = "Test";
                x.Text = ResourceHelpers.Faker.Lorem.Paragraph();
                x.Image = PropertyHelpers.GetOrAddMedia("Image 2", ".png", ResourceHelpers.GetImageStream());
            });
        })
        .WithContent(x => x.Name = "Folder1")
        .WithContent(x => x.Name = "Image 1");

       b.UsePages(ContentReference.RootPage)
        .WithStartPage(p =>
        {
            p.Name = "Home Page";
            p.MainContentArea
            .AddExistingItems(teaser2Ref, teaser3Ref)
            .AddItem("Start Page Teaser", b =>
            {
                b.Heading = ResourceHelpers.Faker.Lorem.Slug();
                b.Text = ResourceHelpers.Faker.Lorem.Paragraph();
                b.Image = PropertyHelpers.GetOrAddMedia("Image 2", ".png", ResourceHelpers.GetImageStream());
            });
        }, CultureInfo.GetCultureInfo("sv"), t =>
        {
            t.Name = "Start Page [SV]";
        }, l1 =>
        {
            l1
            .WithPage(out articlePageRef, p =>
            {
                p.Name = "article1";
                p.MetaTitle = ResourceHelpers.Faker.Lorem.Slug();
                p.TeaserText = ResourceHelpers.Faker.Lorem.Paragraph();
                p.MainBody
                .AddStringFragment(ResourceHelpers.Faker.Lorem.Paragraphs())
                .AddContentFragment(PropertyHelpers.GetOrAddMedia("Image 1", ".png", ResourceHelpers.GetImageStream()))
                .AddStringFragment(ResourceHelpers.Faker.Lorem.Paragraphs());
                p.PageImage = PropertyHelpers.GetOrAddMedia("Image 1", ".png", ResourceHelpers.GetImageStream());
                p.MainContentArea
                .AddItem("Jumbotron Block", b =>
                {
                    b.ButtonText = ResourceHelpers.Faker.Lorem.Slug();
                    b.ButtonLink = new Url(ResourceHelpers.Faker.Internet.Url());
                    b.Heading = ResourceHelpers.Faker.Lorem.Slug();
                })
                .AddItem(options: i =>
                {
                    i.Name = "Test Image";
                    i.ContentLink = PropertyHelpers.GetOrAddMedia("Image 1", ".png", ResourceHelpers.GetImageStream());
                })
                .AddExistingItem(teaser3Ref);
            })
            .WithPages(p =>
            {
                p.Name = "Article 33";
                p.MetaTitle = ResourceHelpers.Faker.Lorem.Slug();
                p.TeaserText = ResourceHelpers.Faker.Lorem.Paragraph();
                p.MainBody.AddStringFragment(ResourceHelpers.Faker.Lorem.Paragraphs(10));
                p.MainContentArea.AddExistingItem(teaser2Ref);
            }, 100);
        })
       .WithPages(p =>
        {
            p.Name = ResourceHelpers.Faker.Lorem.Slug(2);
            p.MainContentArea
            .AddItems(b =>
            {
                b.Heading = ResourceHelpers.Faker.Lorem.Slug();
                b.Text = ResourceHelpers.Faker.Lorem.Paragraph();
                b.Image = PropertyHelpers.GetOrAddMedia("Image 1", ".png", ResourceHelpers.GetImageStream());
            }, 10);
        }, 10)
    });

アセット構造の作成、作成されたコンテンツの参照取得による再利用、翻訳バージョンの作成、無制限のサブアイテムの作成、同じタイプの多数のコンテンツ アイテムの作成が可能になります。 合計 1 ~ 10000 の任意の数値を指定できるパラメータ、特定のユーザーとロールが割り当てられた複数のサイトなど。

パッケージはオープンソースであり、次の URL にあります。 https://github.com/milosranko/CmsContentScaffolding

単体テストの作成に関しては、次の 5 つの重要なポイントを特定できます。

  1. 単体テストの定義
  2. 自動化され、反復可能である必要がある
  3. AAA パターン (Arrange、Act、Assert) を使用して実装と読み取りが簡単である必要があります。
  4. 完全に隔離すべきだ
  5. テスト終了後にリソースをクリーンアップする

まず、専用の単体テスト DB を使用してテストを初期化します (DB を作成および削除するための sa 権限を持つ特別な SQL Server ユーザーを作成する必要があります)。次に、CmsContentScaffolding を使用してコンテンツをシードし、テストを作成し、テスト終了後にリソース (DB を含む) をクリーンアップします。 。

contentLoader を使用して単体テストを実行し、目的のコンテンツを取得し、コントローラー アクションを呼び出して作成されたことを確認できます。

この例では、トリプル A 原則を使用して実装され、コントローラー メソッドが呼び出された場合にテスト メソッドがどのように見えるかを見ていきます。 出力ビュー モデルが期待どおりの状態であることを確認します。

[TestMethod]
public void StartPageController_ShouldReturnIndexViewModel()
{
    //Arrange
    var contentLoader = ServiceLocator.Current.GetRequiredService();
    var siteDefinitionRepository = ServiceLocator.Current.GetRequiredService();
    var siteDefinition = siteDefinitionRepository
        .List()
        .Where(x => x.GetHosts(CultureInfo.GetCultureInfo("sr"), false).Any())
        .Single();
    var startPage = contentLoader.Get(siteDefinition.StartPage);
    var _controller = new StartPageController();

    //Act
    var res = (ViewResult)_controller.Index(startPage);

    //Assert
    Assert.IsNotNull(res);
    Assert.IsInstanceOfType(res.Model, typeof(PageViewModel));
    Assert.IsNotNull(((PageViewModel)res.Model).CurrentPage.MainContentArea);
}

継続的なソフトウェア開発には、実装されたコードを継続的に検証することが重要です。 Optimizely では、CMS フレームワークのコンテンツとサイト構造は重要なコンポーネントであり、望ましくない問題が予期せぬときに発生するのを避けるために、保守し、常に検証する必要があります。 私は前回のプロジェクトで CmsContentScaffolding ライブラリを使用しましたが、単体テスト ヘルパーとして、またはサイト構造を迅速にスキャフォールディングして手動テストを実行し、バグを調査するのに非常に役立つことがわかりました。

ぜひチェックして、このブログ投稿にコメントを残していただければ幸いです。

https://github.com/milosranko/CmsContentScaffolding

2024 年 4 月 26 日

#CmsContentScaffolding #パッケージを使用した単体テストの最適化

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Recent News

Editor's Pick