2

CustomerFactory 経由でのみ作成できる Customer ビジネス エンティティがあります。ただし、Customer オブジェクトを使用するクラスの単体テストを実行する方法について質問があります。単体テストでは、顧客が使用されるたびに Customer とその CustomerFactory のセットアップが必要になるためです。

コンストラクターではなく CustomerFactory を使用する理由は、ICustomerValidator による検証が必要だからです。ただし、検証ロジックをコンストラクター内に配置するには、ICustomerValidator をコンストラクターに挿入する必要があり、これは望ましくない場合があります。

たとえば、ICustomerService の実装の単体テストを実行する場合、Customer と CustomerFactory の作成とセットアップ (さらに、IdValidFirstName などの ICustomerValidator による顧客検証) を含むセットアップ手順を作成する必要があります。さらに、単体テストで Customer インスタンスが使用されるたびに、これらの設定を繰り返す必要があります。

以下は単体テスト中の ICustomerService ですが、以下の Customer のセットアップを作成する必要があります。

この実装を単体テストしたい

    public interface ICustomerService
    {
       bool AddCustomer(Customer customer);
    }

 public class Customer
    {
        internal Customer()
        { }

        public int Id { get; internal set; }

        public string Firstname { get; internal set; }

        public string Surname { get; internal set; }

        public DateTime DateOfBirth { get; internal set; }

        public string EmailAddress { get; internal set; }

        public bool HasCreditLimit { get; internal set; }

        public Company Company { get; internal set; }

        //... other properties
}

ICustomerService と ICustomerFactory の実装はどちらも ICustomerValidator に依存することに注意してください。

     public interface ICustomerFactory
        {
            Customer CreateCustomerWith(int id, string firstName, string surname, DateTime dateOfBirth, string emailAddress, Company company);        
        }

 public class CustomerFactory : ICustomerFactory
    {
        private ICustomerValidator customerValidator;
        public CustomerFactory(ICustomerValidator customerValidator)
        {
            this.customerValidator = customerValidator;
        }

        public Customer CreateCustomerWith(int id, string firstName, string surname, DateTime dateOfBirth,
            string emailAddress, Company company)
        {

        //validation logic here ...
        }
     }



 public interface ICustomerValidator
    {
        IDictionary<string, string> Errors { get; }

        bool IsValid(Customer customer);

        bool IsValidId(int id);

        bool IsValidFirstName(string firstName);

        bool IsValidSurname(string surname);

        bool IsValidDateOfBirth(DateTime dateOfBirth);

        bool IsValidEmailAddress(string emailAddress);

        bool IsValidCompany(Company company);

    }

しかし、ICustomerService の単体テストを実行する際にこれをセットアップする必要があります。これは多くのセットアップのように見えます。または、正しいか、またはより良い方法があります (再利用することはできますが、テストで呼び出す必要があります)。 ICustomerService の場合、それが唯一の方法ですか)?

private Customer CreatCustomer()
        {
            var customerId = 0;
            var firstName = "John";
            var surname = "Tom";
            var emailAddress = "John.Tom@unit.com";
            var dateOfBirth = new DateTime(2013, 1, 1);
            var company = new Company(34, "Unit", Classification.VIP);
            SetupForCustomerCreation(customerId,firstName,surname,emailAddress,dateOfBirth,company);

            var customer = this.customerFactory
                                        .CreateCustomerWith(
                                            customerId, firstName, surname, dateOfBirth, emailAddress, company);

            return customer;
        }

        private void SetupForCustomerCreation(int customerId, string firstName, string surname, string emailAddress, DateTime dateOfBirth, Company company)
        {
            this.customerValidatorMock.Setup(c => 
                                                c.IsValidId(customerId)).Returns(true);
            this.customerValidatorMock.Setup(c => 
                                                c.IsValidFirstName(firstName)).Returns(true);
            this.customerValidatorMock.Setup(c => 
                                                c.IsValidSurname(surname)).Returns(true);
            this.customerValidatorMock.Setup(c => 
                                                c.IsValidDateOfBirth(dateOfBirth)).Returns(true);
            this.customerValidatorMock.Setup(c => 
                                                c.IsValidEmailAddress(emailAddress)).Returns(true);
            this.customerValidatorMock.Setup(c => 
                                                c.IsValidCompany(company)).Returns(true);
        }

前もって感謝します!

4

2 に答える 2

1

Customer コンストラクターを公開することをお勧めします。そうすれば、いつでも工場に触れることなく自由に使用できます。クラスに not public コンストラクターを導入すると、暗黙的にそのファクトリに依存するようになりますが、これはほとんどの場合推奨されません。保守とテストが容易になるため、クラスを疎結合にすることをお勧めします。

于 2013-07-15T10:32:45.180 に答える
0

@Alexandr-Mihalciucが正しいアプローチに答えるよう強くお勧めしますが、顧客クラスがInternalsVisibleとして定義されているアセンブリをテストアセンブリに公開し、テストで顧客クラスのインスタンスを作成できるようにすることができます。内部ctorを保持します。

于 2013-07-15T16:49:57.670 に答える