2017-08-05 34 views
0

我正在嘗試在我的InsertCashTransaction類中對方法Execute()進行單元測試。我想測試它是否正確地爲User.Balance分配一個新值。你可以在這裏看到兩班如何對一個方法正確地分配一個新值給另一個類進行單元測試

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"); 
     } 
    } 
} 

User類

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; 
    } 
} 

我到目前爲止已經試過創建用戶的界面並通過Nsubsitute試圖在考試中替代你的班級看到這裏

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); 

    } 

我的實際問題 當我嘗試運行測試,我得到一個Nullreference例外,我的問題是我不知道我在做什麼錯了。問題似乎是每當icTransaction.Execute()被調用時。我希望你能幫我弄清楚我做錯了什麼。

請問是否有什麼不清楚,需要進一步解釋

+0

您初始化'公共InsertCashTransaction(IUSER UserI) { this._userI = UserI; }'但在'Execute'方法中,您可以檢索User.Balance + Amount值。你確定你發佈了所有'InsertCashTransaction'類的代碼,或者它是錯誤的嗎? –

+0

我已經發布了來自InsertCashTransaction類的所有代碼 – Lumbaz

+0

看起來你的第二個構造函數沒有正確初始化基類,所以'User'是'null'。嘗試移除該構造函數,而是讓第一個構造函數使用'IUser'而不是'User'(您還需要對基類構造函數進行相同的更改)。然後在單元測試中使用三參數構造函數。 – lesscode

回答

0

您似乎有範圍問題。

  • 您的構造函數需要:用戶,日期和金額作爲參數。當你只用User初始化你的類時,其他的params就會變爲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 user = 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

相關問題