2017-08-05 5 views
0

InsertCashTransactionクラスでメソッドExecute()をユニットテストしようとしています。私はそれが正しくUser.Balanceに新しい値を割り当てるかどうかテストしたい。あなたはここでは2つのクラスを参照することができますメソッドが別のクラスに新しい値を正しく割り当てることをユニットテストする方法

InsertCashTransactionクラス

public class InsertCashTransaction : Transaction 
{ 
    private IUser _userI; 
    public InsertCashTransaction(User user, DateTime date, decimal amount) : base(user, date, amount) 
    { 
     User = user; 
    } 

    public InsertCashTransaction(IUser UserI) 
    { 
     this._userI = UserI; 
    } 

    public override string ToString() 
    { 
     return $"Transaction number: {TransactionId}, Date: {Date}: {Amount} has been inserted onto {User.Username}'s wallet."; 
    } 

    // Method I am trying to test 
    public override void Execute() 
    { 
     if (Amount > 0) 
     { 
      User.Balance = User.Balance + Amount; 
     } 
     else if (Amount <= 0) 
     { 
      throw new ArgumentException("Not allowed to withdraw from users balance nor insert 0"); 
     } 
    } 
} 

私はこれまで、ユーザーのインターフェイスを作成しようとした

public class User : IUser 
{ 
    private int _userid; 
    private string _firstname; 
    private string _lastname; 
    private string _username; 
    private string _email; 
    private decimal _balance; 

    public int UserID 
    { 
     get { return _userid; } 
     set 
     { 
      if (value < 1) 
      { 
       throw new ArgumentException("ID cannot be below one"); 
      } 
      _userid = value; 
     } 
    } 

    public string FirstName 
    { 
     get { return _firstname; } 
     set 
     { 
      CheckIfNull(value); 
      ValidateName(value); 
      _firstname = value; 
     } 
    } 

    public string LastName 
    { 
     get { return _lastname; } 
     set 
     { 
      CheckIfNull(value); 
      ValidateName(value); 
      _lastname = value; 
     } 
    } 

    public string Username 
    { 
     get { return _username; } 
     set 
     { 

      CheckIfNull(value); 
      foreach (char item in value) 
      { 
       if (char.IsUpper(item)) 
       { 
        throw new ArgumentException("Username is not allowed to hold use upper case letter"); 
       } 

       if (char.IsSymbol(item)) 
       { 
        throw new ArgumentException("Username must not contains symbols"); 
       } else if (item == '-') 
       { 
        throw new ArgumentException("Username must not contain symbols"); 
       } 
      } 
      _username = value; 
     } 
    } 

    public string Email 
    { 
     get { return _email; } 
     set 
     { 
      CheckIfNull(value); 
      //Creates two out of the email separated by @ 
      string[] separation = value.Split('@'); 
      string localPart = separation[0]; 
      string domain = separation[1]; 
      foreach (char item in localPart) 
      { 
       if (char.IsLetterOrDigit(item) == false) 
       { 
        if (item != '.' || item != '-' || item != '_' || item != ',') 
        { 
         continue; 
        } 
        else 
        { 
         throw new ArgumentException("Not a valid email"); 
        } 
       } 
      } 
      // Check if domain starts with '.' or '-' 
      if (domain.Contains(".")) 
      { 
       if (domain.StartsWith(".") || domain.StartsWith("-") || domain.EndsWith(".") || domain.EndsWith("-")) 
       { 
        throw new ArgumentException("domain must not start with ."); 
       } 
      } 
      foreach (char item in domain) 
      { 
       if (char.IsSymbol(item)) 
       { 
        throw new ArgumentException("Domain must not contain any symbols"); 
       } 
      } 
      _email = value; 
     } 
    } 

    public decimal Balance 
    { 
     get { return _balance; } 
     set 
     { 
      if (value < 0) 
      { 
       throw new ArgumentException("Balance is below 0"); 
      } 
      _balance = value; 
     } 
    } 

    public override string ToString() 
    { 
     return $"{FirstName}, {LastName}, {Email}"; 
    } 

    public override bool Equals(object obj) 
    { 
     if (obj == null) 
     { 
      return false; 
     } 
     if (this.GetType() != obj.GetType()) 
     { 
      return false; 
     } 
     return Equals((User)obj); 
    } 

    public bool Equals(User obj) 
    { 
     if (obj == null) 
     { 
      return false; 
     } 

     if (ReferenceEquals(this, obj)) 
     { 
      return true; 
     } 

     if (this.GetHashCode() != obj.GetHashCode()) 
     { 
      return false; 
     } 
     System.Diagnostics.Debug.Assert(base.GetType() != typeof(object)); 
     if (!base.Equals(obj)) 
     { 
      return false; 
     } 
     return UserID.Equals(obj.UserID); 
    } 

    public override int GetHashCode() 
    { 
     return UserID.GetHashCode(); 
    } 

    public int CompareTo(User user) 
    { 
     if (UserID > user.UserID) 
     { 
      return -1; 
     } 
     return 1; 
    } 

    public User(int id, string firstName, string lastName, string username, string email, decimal balance) 
    { 
     UserID = id; 
     FirstName = firstName; 
     LastName = lastName; 
     Username = username; 
     Email = email; 
     Balance = balance; 
    } 

    public User() 
    { 
    } 

    public string CheckIfNull(string element) 
    { 
     if (string.IsNullOrEmpty(element)) 
     { 
      throw new ArgumentNullException("Something is missing"); 
     } 
     return element; 
    } 

    protected string ValidateName(string name) 
    { 
     foreach (char item in name) 
     { 
      if (char.IsDigit(item)) 
      { 
       throw new ArgumentException("Something is wrong in either firstname or lastname"); 
      } 
     } 
     return name; 
    } 
} 

Userクラスクラスとvia Nsubsituteはあなたができるテストのクラスの代用をしようとしました私の実際の問題 、私はテストを実行しようとすると、私はNullreferenceの例外を取得

IUSERインタフェース

public interface IUser 
{ 
    int UserID { get; set; } 
    string FirstName { get; set; } 
    string LastName { get; set; } 
    string Username { get; set; } 
    string Email { get; set; } 
    decimal Balance { get; set; } 
} 

InsertCashTransactionTestクラス

[TestFixture] 
class InsertCashTransactionTest 
{ 
    [TestCase(0)] 
    [TestCase(-1)] 
    [TestCase(-10)] 
    [TestCase(-50)] 
    public void AmountBelowZero_throwException(decimal number) 
    { 
     IUser user = Substitute.For<IUser>(); 
     InsertCashTransaction icTransaction = new InsertCashTransaction(user); 
     icTransaction.Amount = number; 
     Assert.Catch<ArgumentException>(() => icTransaction.Execute()); 
    } 

    // Test that isn't working 
    [TestCase(1)] 
    [TestCase(10)] 
    [TestCase(50)] 
    public void AmountAboveZero_InsertToUserBalance(decimal number) 
    { 
     //Arrange 
     IUser user = Substitute.For<IUser>(); 
     InsertCashTransaction icTransaction = new InsertCashTransaction(user); 
     user.Balance = 0; 
     icTransaction.Amount = number; 
     decimal actualresult = number; 
     // Act 
     // Somewhere here it goes wrong 
     icTransaction.Execute(); 
     //Assert 
     Assert.AreEqual(actualresult, user.Balance); 

    } 

にここを参照してください、私の問題があります私はどこで、何が間違っているのか分かりません。問題は、icTransaction.Execute()が呼び出されるたびに発生するようです。あなたが私が間違っていることを理解する助けになることを願っています。

何かが不明確であり、さらにあなたはスコープの問題を抱えているように見える

+0

あなたは 'パブリックInsertCashTransaction(たIUser UserI) { this._userI = UserIを初期化します。 } '' Execute'メソッドでは 'User.Balance + Amount'の値を取得します。あなたは 'InsertCashTransaction'クラスのすべてのコードを投稿したのでしょうか、間違っていますか? –

+0

InsertCashTransactionクラスからすべてのコードを投稿しました – Lumbaz

+0

2番目のコンストラクタが基本クラスを正しく初期化していないようです。そのため、 'User'は' null'です。そのコンストラクタを削除して、最初のコンストラクタに 'User'の代わりに' IUser'を渡すようにしてください(あなたは基本クラスのコンストラクタにも同じ変更を加える必要があります)。その後、単体テストで3パラメータコンストラクタを使用します。 – lesscode

答えて

0

を説明する必要がある場合はお問い合わせください。

  • コンストラクタには、User、Date、Amountが必須です。ユーザーのみでクラスを初期化すると、他のパラメータはnullになります。見てみな。ネイティブ型の名前を持つ変数を宣言

    [TestCase(1)] 
    [TestCase(10)] 
    [TestCase(50)] 
    public void AmountAboveZero_InsertToUserBalance(decimal number) 
    { 
        //Arrange 
        IUser user = Substitute.For<IUser>(); 
        InsertCashTransaction icTransaction = new InsertCashTransaction(user, null, number); 
        user.Balance = 0; 
        decimal actualresult = number; 
        // Act 
        // Somewhere here it goes wrong 
        icTransaction.Execute(); 
        //Assert 
        Assert.AreEqual(actualresult, user.Balance); 
    } 
    

ノート避けます。例:数、ブール、整数、など

  • ユーザーベースは両親(グッドプラクティスときれいなコード)を参照します

    if (base.Amount <= 0) 
    { 
        throw new ArgumentException("Not allowed to withdraw from users balance nor insert 0"); 
    } 
    User.Balance = User.Balance + base.Amount; 
    

誤りがあるかもしれないどこが失われた場合。エラーのファイル、行、位置を確認できるコンソールの出力を確認してください。また、エラー出力エラーを共有することで、問題を容易に追跡できるようになりました。

+0

変更するポイントのコード自体を追加しました。さらに、私は、ソリューションを手に入れるよりも理解が良いと信じているので、理由を打ち明けました。 – Cleriston

+0

これはばかげた質問かもしれません。しかし、それは私にラインIuserユーザー= subtitute.for を削除し、単にサンプルユーザーを書く必要がありますか? – Lumbaz

+0

私は問題があなたのユーザコンストラクタにあるとは思わない。全く馬鹿じゃない。私はあなたの答えに詳細を記入するためにあなたの経験レベルを知らせることをお勧めします。 – Cleriston

1

投稿コードから、私はこの場合にはUserを嘲笑する必要はないと思います。モッキングは、主に、特定の副作用、非決定論、依存関係、または速度のためにテストするのが難しいクラスに代わるものです。 例としては、電子メールの送信、完全なデータベースの設定、またはさまざまなネットワーク状態のシミュレーションなどがあります。

ポイント@Cleristonのアドレス指定だけでなく、IUserインターフェイスを削除し、代わりに実際のUserインスタンスを使用することをお勧めします。あなたは、その後のようなものを使用して、実際のロジックのテストを書くことができます。

[TestCase(1)] 
[TestCase(10)] 
[TestCase(50)] 
public void AmountAboveZero_InsertToUserBalance(decimal number) 
{ 
    //Arrange 
    var user = new User(1, "FirstName", "Surname", "tst", "[email protected]", 0); 
    var icTransaction = new InsertCashTransaction(user, DateTime.Now, number); 
    // Act 
    icTransaction.Execute(); 
    //Assert 
    Assert.AreEqual(number, user.Balance); 
} 
+1

これまで私はこれをやってきました。あなたのコメントは、クラスを模擬して模擬するか実際のユーザのインス​​タンスを使うかはわからないため、私の心の中から疑いの余地がなくなりました。 – Lumbaz

関連する問題