我正在尝试对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尝试在测试中替换类,您可以在这里看到
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 :(得分: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", "tst@example.com", 0);
var icTransaction = new InsertCashTransaction(user, DateTime.Now, number);
// Act
icTransaction.Execute();
//Assert
Assert.AreEqual(number, user.Balance);
}
答案 1 :(得分:0)
你似乎有范围问题。
您的构造函数需要:User,Date和Amount作为参数。当您仅使用User初始化类时,其他参数将为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;
当您迷路时可能出现错误。检查控制台的输出,您可以在其中找到错误的文件,行和位置。另外,共享错误输出错误也可以更轻松地跟踪您的问题。