I have these 3 methods for ATM mock program.
public decimal CheckBalance(BankAccount account)
{
return account.AccountBalance;
}
public void Deposit(BankAccount account, BankTransaction bankTransaction)
{
account.AccountBalance += bankTransaction.TransactionAmount;
}
public void Withdraw(BankAccount account, BankTransaction bankTransaction)
{
if(bankTransaction.TransactionAmount > account.AccountBalance)
{
throw new Exception("Withdraw failed. Transaction amount is more than account balance.");
}
account.AccountBalance -= bankTransaction.TransactionAmount;
}
And here are my xUnit unit test methods. The test data is in-memory for this version.
[Theory, MemberData(nameof(CheckBalanceShouldReturnValidBalanceAmount_Data))]
public void CheckBalanceShouldReturnValidBalanceAmount(BankAccount account, decimal accountBalance)
{
// Act
var balance = _atm.CheckBalance(account);
// Assert
Assert.Equal(accountBalance, balance);
}
[Theory, MemberData(nameof(DepositShouldPass_Data))]
public void DepositShouldPass(BankAccount account, BankTransaction bankTransaction, BankAccount accountExpected)
{
// Act
_atm.Deposit(account, bankTransaction);
var balance = _atm.CheckBalance(account);
// Assert
Assert.Equal(accountExpected.AccountBalance, balance);
}
[Theory, MemberData(nameof(WithdrawShouldPass_Data))]
public void WithdrawShouldPass(BankAccount account, BankTransaction bankTransaction, BankAccount accountExpected)
{
// Act
_atm.Withdraw(account, bankTransaction);
var balance = _atm.CheckBalance(account);
// Assert
Assert.Equal(accountExpected.AccountBalance, balance);
}
[Theory, MemberData(nameof(WithdrawAmountMoreThanBalanceShouldFail_Data))]
public void WithdrawAmountMoreThanBalanceShouldFail(BankAccount account, BankTransaction bankTransaction)
{
// Assert and Act
var exception = Assert.Throws<Exception>(() => _atm.Withdraw(account, bankTransaction));
Assert.Equal("Withdraw failed. Transaction amount is more than account balance.",
exception.Message);
}
All tests passed successfully. Any comments on coding style of unit test?
Edited After Answer with extra class:
namespace XUnitSample.ClassLib.Models
{
public class BankAccount
{
public int Id { get; set; }
public int BankAccountNo { get; set; }
public decimal AccountBalance { get; set; }
}
}
namespace XUnitSample.ClassLib.Models
{
public class BankTransaction
{
public int Id { get; set; }
public decimal TransactionAmount { get; set; }
public TransactionTypeEnum TransactionType { get; set; }
}
public enum TransactionTypeEnum
{
Deposit, Withdraw, ThirdPartyTransfer
}
}
1 Answer 1
Is your mock ATM class literally named _atm
?! Or is it a non-static class that you have assigned to an instance named _atm
? Either way, I don't like it and find the _atm
class to be useless in your limited example.
The BankAccount
class, which you do not share, should have a Deposit
and Withdraw
method, both accepting a BankTransaction
as a input argument. You should include validation of a particular transaction within each method, i.e. do not accept a deposit of negative amount. You also do not share BankTransaction
with us.
CheckBalance
is not needed, as you would just as easily show the BankAccount.AccountBalance
property. Also the property name could be shortened to Balance
since it is the balance of the bank account.
-
\$\begingroup\$ My ATM class is named as
AtmApp
. Yeah, it is a non-static class and I instantiate it in my constructor at thisAtmAppTest
class and name the instance as_atm
. I have addedBankAccount
andBankTransaction
class at my original post. But these class is anemic. Oh this meansDeposit
andWithraw
method should moved toBankAccount
. Okay, thanks. \$\endgroup\$Steve Ngai– Steve Ngai2020年06月15日 23:08:22 +00:00Commented Jun 15, 2020 at 23:08