【发布时间】:2017-08-05 12:46:04
【问题描述】:
我正在尝试在我的 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");
}
}
}
用户类
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 类的接口,并通过 Nsubsitute 尝试替换测试中的类,您可以在此处看到
用户界面
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() 被调用。我希望你能帮助我找出我做错了什么。
如果有不清楚的地方需要进一步解释,请询问
【问题讨论】:
-
您初始化了
public InsertCashTransaction(IUser UserI) { this._userI = UserI; },但在Execute方法中,您检索了User.Balance + Amount值。你确定你发布了InsertCashTransaction类的所有代码还是错误的? -
我已经发布了 InsertCashTransaction 类中的所有代码
-
看起来你的第二个构造函数没有正确初始化基类,所以
User是null。尝试删除该构造函数,并让您的第一个构造函数采用IUser而不是User(您还需要对基类构造函数进行相同的更改)。然后在单元测试中使用三参数构造函数。
标签: c# unit-testing nsubstitute