C#でドメイン駆動開発【DDD】エラー処理とExceptionの書き方!⑬

当サイトではアフィリエイト広告を利用しています。

C#でドメイン駆動開発

プログラムにはエラー処理が必要です。ドメイン駆動開発とは直接関係はないですが

最後にエラー処理の書き方について解説します。

エラー処理に関して

Save時に今はエラーチェックをしていません。

MeasureValueを空文字で実行するとFormatExceptionが発生します。

 

シナリオとしては空文字なら

「計測値を入力してください」というメッセージを表示するのが適切です。

 

次は適切にエラーチェックがされていることのテストコードを書いていきましょう。

 

MeasureSaveViewModelTestに新しいテストメソッドを作成します。

 [TestMethod]
 public void 計測登録_シナリオ_エラーチェック()
 {
     var measureMock = new Mock<IMeasureRepository>();
     var viewModelMock = new Mock<MeasureSaveViewModel>(measureMock.Object);
     viewModelMock.Setup(x => x.GetDateTime()).Returns("2017/01/03 13:00:00".ToDate());
     var viewModel = viewModelMock.Object;
       var ex = AssertEx.Throws<MessageException>(() => viewModel.Save());
     ex.Message.Is("計測値を入力してください");
 }

途中までは一つ目のテストと同じ内容です。

異なるのはvar ex = AssertEx.Throwsの部分です。

 

ここではviewModelのSaveを実行したときに,

MessageExceptionが通知されることをテストしています。

 

その次の行ではその例外のMessageの内容を検査しています。

ここではMeasureValueが初期値の空文字の状態で

Saveを行うとエラー通知が行われるテストをしています。

 

MessageExceptionは意図していない例外と切り分けるために

独自で作成した例外クラスです。

 

ドメイン層にExceptionsというフォルダを作成し,

その中に作成します。

 

MessageExceptionなどの独自で作成した例外は例外レベルを

判断できるようにべって「ExceptionBase」という抽象クラスを継承し,

またその中で「ExceptionType」という列挙体で例外の種類を切り分けています。

namespace DDD.Domain.Exceptions
{
 public sealed class MessageException : ExceptionBase
 {
     public MessageException(ExceptionType exceptionType, string message) : base(exceptionType, message)
     {
     }
 }

 

using System;
namespace DDD.Domain.Exceptions
{
 public abstract class ExceptionBase : Exception
 {
     public ExceptionBase(ExceptionType exceptionType, string message) : base(message)
     {
         ExceptionType = exceptionType;
     }
     public ExceptionType ExceptionType { get; }
 }
}

 

namespace DDD.Domain.Exceptions
{
    public enum ExceptionType
    {
        Information,
        Warning,
        Error,
    }
}

テストを実行してみます。

NGになります。

 

MeasureSaveViewModelのSaveメソッドに次のコードを追加します。

 public void Save()
 {
     Guard.IsNullOrEmptyMessage(MeasureValue, "計測値を入力してください");
     var measureValue = Convert.ToSingle(MeasureValue);
     var entity = new MeasureEntity(
         Guid.NewGuid().ToString(),
         MeasureDate,
         measureValue);
       _measureRepository.Save(entity);
 }

 

Guardクラスは,チェック関連をまとめた静的クラスです。

エラーチェックはいくつかのパターンが決まってくるため,

各クライアントコードでNullチェックなどのif分を書かずに

1行で済ませられるように,

このような静的クラスをまとめています。

 

Guardクラスはドメイン層のHelpersフォルダに入れています。

このようにビジネスロジックを含まない共通コードはHelpersに入れておきます。

 public static void IsNullOrEmptyMessage(string value, string message)
 {
     IsNullOrEmptyMessage(value, message, ExceptionType.Information);
 }
public static void IsNullOrEmptyMessage(string value, string message, ExceptionType exceptionType)
 {
     if (string.IsNullOrEmpty(value))
     {
         throw new MessageException(exceptionType, message);
     }
 }

これでテストを実行すると成功します。

それではUIとインフラストラクチャを作成しましょう。

Viewsフォルダに「MeasureSaveView」フォームを作成します。

計測日時はDateTimePickerでNameはMeasureDateTextBox,

計測値はTextBoxでNameはMeasureValueTextBox,

label3はNameをUnitLabel,SaveボタンはNameをSaveButtonとします。

画面のコードを開きます。

 

public partial class MeasureSaveView : BaseForm
 {
     public MeasureSaveView()
     {
         InitializeComponent();
           var viewModel = new MeasureSaveViewModel();
         MeasureDateTextBox.DataBindings.Add("Value", viewModel, nameof(viewModel.MeasureDate));
         MeasureValueTextBox.DataBindings.Add("Text", viewModel, nameof(viewModel.MeasureValue));
         UnitLabel.DataBindings.Add("Text", viewModel, nameof(viewModel.UnitLabel));
         SaveButton.Click += (sender, e) => viewModel.Save();
     }
 }

MeasureSaveViewModelの生成でコンパイルエラーが出るため,

以下のコンストラクタを追記します。

 public MeasureSaveViewModel() : this(Factories.CreateMeasureRepository())
 {
 }

MeasureFakeのSaveメソッドが未実装のため追記します。

 public void Save(MeasureEntity entity)
 {
     var index = _entities.FindIndex(x => x.MeasureId == entity.MeasureId);
     if(index >=0)
     {
         _entities[index] = entity;
         return;
     }
 
     _entities.Add(entity);
 }

ここでは,すでにMeasureIdが存在している場合は,

値の変更。存在していない場合は追加しています。

最後までお読みいただきありがとうございました。
さらにドメイン駆動を学びたいという勉強家の方は
頭のいい先人の本を是非読んでみてください。

C#でドメイン駆動開発をするうえで私が参考にした書籍ランキング!
私はメーカーでC#などを使った製品開発をしています。 メーカーの辛さは,製品リリースされたら,ソフトのメンテナンスが必要なことです。 派遣プログラマー時代は,プログラムを作ったら他の現場に派遣されるので, 作った後の世話をする必要がありませ...