├── chapter2 ├── codestructures.py └── FooExamples.java ├── README.md ├── chapter4 ├── bankService │ ├── Check.java │ ├── exceptions │ │ ├── InvalidAmountException.java │ │ └── InsufficientFundsException.java │ ├── Customer.java │ ├── Account.java │ ├── SavingsAccount.java │ ├── Banking.java │ ├── SavingsAccountTest.java │ ├── CheckingAccountTest.java │ ├── CheckingAccount.java │ └── BankService.java ├── notificationService │ ├── Notification.java │ └── EmailService.java ├── CustomerTest.java └── bankApplication │ └── Bank.java ├── chapter5 ├── bankService │ ├── Check.java │ ├── exceptions │ │ ├── InvalidAmountException.java │ │ └── InsufficientFundsException.java │ ├── Customer.java │ ├── Account.java │ ├── SavingsAccount.java │ ├── Banking.java │ ├── SavingsAccountTest.java │ ├── CheckingAccountTest.java │ ├── CheckingAccount.java │ └── BankService.java ├── notificationService │ ├── Notification.java │ └── EmailService.java ├── CustomerTest.java └── bankApplication │ └── Bank.java ├── chapter3 ├── ParameterizedTestExample.cs └── ObscureTestExample.cs └── chapter6 ├── sql ├── CreateUndoOpenValidationSp.sql └── TestUndoOpenValidationSp.sql ├── lib └── RatingScaleLevelsValidator.js └── _test_ └── RatingScaleLevelsValidator.test.js /chapter2/codestructures.py: -------------------------------------------------------------------------------- 1 | def seq(x,y) : 2 | z = x + y 3 | return z 4 | 5 | def condition (x) : 6 | if x > 10: 7 | z = x + 10 8 | else: 9 | z = x -10 10 | return z 11 | 12 | def loop(List): 13 | for l in List: 14 | do_function(l) 15 | return results -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Testing From The Inside: Unit Testing Edition 2 | Code from course "Testing From The Inside: Unit Testing Edition" by Tariq King on Test Automation University 3 | https://testautomationu.applitools.com/unit-testing/ 4 | 5 | Learn the fundamentals of unit testing by applying code-based techniques such as white box testing, mocking, code coverage analysis, and more. 6 | -------------------------------------------------------------------------------- /chapter4/bankService/Check.java: -------------------------------------------------------------------------------- 1 | package bankService; 2 | 3 | /** 4 | * Interface for extracting information from Checks using optical character recognition. 5 | * @author Tariq King 6 | */ 7 | public interface Check 8 | { 9 | public double getAmount(); 10 | public int getCheckNumber(); 11 | } 12 | 13 | // TODO: Interface needs to be implemented. Lead developer is on vacation. -------------------------------------------------------------------------------- /chapter4/bankService/exceptions/InvalidAmountException.java: -------------------------------------------------------------------------------- 1 | package bankService.exceptions; 2 | 3 | /** 4 | * Thrown whenever an invalid amount is passed to a given transaction. 5 | * @author Tariq King 6 | */ 7 | public class InvalidAmountException extends Exception { 8 | public InvalidAmountException() { 9 | super("Invalid amount for transaction."); 10 | } 11 | 12 | } -------------------------------------------------------------------------------- /chapter5/bankService/Check.java: -------------------------------------------------------------------------------- 1 | package bankService; 2 | 3 | /** 4 | * Interface for extracting information from Checks using optical character recognition. 5 | * @author Tariq King 6 | */ 7 | public interface Check 8 | { 9 | public double getAmount(); 10 | public int getCheckNumber(); 11 | } 12 | 13 | // TODO: Interface needs to be implemented. Lead developer is on vacation. -------------------------------------------------------------------------------- /chapter5/bankService/exceptions/InvalidAmountException.java: -------------------------------------------------------------------------------- 1 | package bankService.exceptions; 2 | 3 | /** 4 | * Thrown whenever an invalid amount is passed to a given transaction. 5 | * @author Tariq King 6 | */ 7 | public class InvalidAmountException extends Exception { 8 | public InvalidAmountException() { 9 | super("Invalid amount for transaction."); 10 | } 11 | 12 | } -------------------------------------------------------------------------------- /chapter4/notificationService/Notification.java: -------------------------------------------------------------------------------- 1 | package notificationService; 2 | 3 | /** 4 | * Interface specifying messaging capabilities. 5 | * @author Tariq King 6 | */ 7 | public interface Notification { 8 | 9 | public void notify(String message, String recipient); 10 | 11 | public void connect(); 12 | 13 | public void disconnect(); 14 | 15 | public boolean isConnected(); 16 | 17 | } -------------------------------------------------------------------------------- /chapter5/notificationService/Notification.java: -------------------------------------------------------------------------------- 1 | package notificationService; 2 | 3 | /** 4 | * Interface specifying messaging capabilities. 5 | * @author Tariq King 6 | */ 7 | public interface Notification { 8 | 9 | public void notify(String message, String recipient); 10 | 11 | public void connect(); 12 | 13 | public void disconnect(); 14 | 15 | public boolean isConnected(); 16 | 17 | } -------------------------------------------------------------------------------- /chapter4/bankService/exceptions/InsufficientFundsException.java: -------------------------------------------------------------------------------- 1 | package bankService.exceptions; 2 | 3 | /** 4 | * Thrown whenever there are insufficient funds in an account to process a given transaction. 5 | * @author Tariq King 6 | */ 7 | public class InsufficientFundsException extends Exception { 8 | public InsufficientFundsException() { 9 | super("Insufficient funds for transaction."); 10 | } 11 | 12 | } -------------------------------------------------------------------------------- /chapter5/bankService/exceptions/InsufficientFundsException.java: -------------------------------------------------------------------------------- 1 | package bankService.exceptions; 2 | 3 | /** 4 | * Thrown whenever there are insufficient funds in an account to process a given transaction. 5 | * @author Tariq King 6 | */ 7 | public class InsufficientFundsException extends Exception { 8 | public InsufficientFundsException() { 9 | super("Insufficient funds for transaction."); 10 | } 11 | 12 | } -------------------------------------------------------------------------------- /chapter3/ParameterizedTestExample.cs: -------------------------------------------------------------------------------- 1 | public class ParameterizedTestExample { 2 | 3 | [TestCase(-1, 3, 3, Description = "Positive Times Negative")] 4 | [TestCase(1, 3, 3, Description = "Two Positives")] 5 | public void MultiplyingTwoNumbersProducesCorrectResult(int first, int second, int expected) 6 | { 7 | var calculator = new Calculator(); 8 | var result = calculator.Multiply(first, second); 9 | result.Should().Be(expected); 10 | } 11 | } -------------------------------------------------------------------------------- /chapter3/ObscureTestExample.cs: -------------------------------------------------------------------------------- 1 | public class ObscureTestExample { 2 | 3 | [Test] 4 | public void MultiplyPositiveByNegativeProducesCorrectResult() 5 | { 6 | MultiplyTwoNumnbersAndAssertTheCorrectValueAndThatOperationIsValid(-1, 3, -3, true); 7 | } 8 | 9 | [Test] 10 | public void MultiplyTwoPositiveNumbersProducesCorrectResult() 11 | { 12 | MultiplyTwoNumbersAndAssertTheCorrectValueAndThatOperationIsValid(1, 3, 3, true); 13 | } 14 | } -------------------------------------------------------------------------------- /chapter2/FooExamples.java: -------------------------------------------------------------------------------- 1 | public class FooExamples { 2 | 3 | public void Foo(Window SSN) 4 | { 5 | if (SSN.Text == "246779876") { 6 | int[] arr = new int[32]; 7 | for (int i = 0; i < 100; i++) 8 | arr[i] = i; 9 | } 10 | else 11 | // Actual code to process the SSN 12 | return; 13 | } 14 | 15 | public int foo(int a) 16 | { 17 | int a = 24; 18 | int b = 25; 19 | int c; 20 | c = a << 2; 21 | return c; 22 | b = 24; 23 | return 0; 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /chapter4/notificationService/EmailService.java: -------------------------------------------------------------------------------- 1 | package notificationService; 2 | 3 | /** 4 | * Wraps an external service used for sending notifications to customers via e-mail. 5 | * @author Tariq King 6 | */ 7 | public class EmailService implements Notification { 8 | 9 | private boolean connected; 10 | 11 | public EmailService() 12 | { 13 | this.connected=false; 14 | } 15 | 16 | @Override 17 | public void notify(String message, String recipient) { 18 | // Send message call to external service 19 | } 20 | 21 | public void connect() { connected=true; }; 22 | 23 | public void disconnect () { connected = false; } 24 | 25 | public boolean isConnected() { return this.connected; } 26 | 27 | } -------------------------------------------------------------------------------- /chapter5/notificationService/EmailService.java: -------------------------------------------------------------------------------- 1 | package notificationService; 2 | 3 | /** 4 | * Wraps an external service used for sending notifications to customers via e-mail. 5 | * @author Tariq King 6 | */ 7 | public class EmailService implements Notification { 8 | 9 | private boolean connected; 10 | 11 | public EmailService() 12 | { 13 | this.connected=false; 14 | } 15 | 16 | @Override 17 | public void notify(String message, String recipient) { 18 | // Send message call to external service 19 | } 20 | 21 | public void connect() { connected=true; }; 22 | 23 | public void disconnect () { connected = false; } 24 | 25 | public boolean isConnected() { return this.connected; } 26 | 27 | } -------------------------------------------------------------------------------- /chapter4/bankService/Customer.java: -------------------------------------------------------------------------------- 1 | package bankService; 2 | 3 | /** 4 | * Facilitates storing, retrieving, and updating customer information. 5 | * @author Tariq King 6 | */ 7 | public class Customer { 8 | 9 | private String name; 10 | private String address; 11 | private String email; 12 | 13 | public Customer(String name, String address, String email) { 14 | this.name = name; 15 | this.address = address; 16 | this.email = email; 17 | } 18 | 19 | public String getName() { 20 | return name; 21 | } 22 | 23 | public void updateName(String name) { 24 | this.name = name; 25 | } 26 | 27 | public String getAddress() { 28 | return address; 29 | } 30 | 31 | public void updateAddress(String address) { 32 | this.address = address; 33 | } 34 | 35 | public String getEmail() { 36 | return email; 37 | } 38 | 39 | public void updateEmail(String email) { 40 | this.email = email; 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /chapter5/bankService/Customer.java: -------------------------------------------------------------------------------- 1 | package bankService; 2 | 3 | /** 4 | * Facilitates storing, retrieving, and updating customer information. 5 | * @author Tariq King 6 | */ 7 | public class Customer { 8 | 9 | private String name; 10 | private String address; 11 | private String email; 12 | 13 | public Customer(String name, String address, String email) { 14 | this.name = name; 15 | this.address = address; 16 | this.email = email; 17 | } 18 | 19 | public String getName() { 20 | return name; 21 | } 22 | 23 | public void updateName(String name) { 24 | this.name = name; 25 | } 26 | 27 | public String getAddress() { 28 | return address; 29 | } 30 | 31 | public void updateAddress(String address) { 32 | this.address = address; 33 | } 34 | 35 | public String getEmail() { 36 | return email; 37 | } 38 | 39 | public void updateEmail(String email) { 40 | this.email = email; 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /chapter6/sql/CreateUndoOpenValidationSp.sql: -------------------------------------------------------------------------------- 1 | CREATE PROCEDURE [dbo].[ValidateUndoOpen] 2 | @PayGroup char(6) = NULL, 3 | @PerControl char(9) = NULL 4 | AS 5 | 6 | /** 7 | * A validation helper for payroll undo functionality. 8 | */ 9 | 10 | SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; 11 | 12 | SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED 13 | BEGIN 14 | 15 | SET NOCOUNT ON 16 | 17 | SELECT 18 | CASE WHEN 19 | ( 20 | SELECT TOP 1 MbtPayGroup 21 | FROM dbo.M_Batch WITH (NOLOCK) 22 | WHERE MbtPayGroup = @PayGroup AND 23 | MbtPerControl = @PerControl AND 24 | (MbtPrinted = 'Y' OR MbtPostOnly = 'Y') 25 | ) 26 | IS NULL THEN 0 ELSE 1 END AS HasPrintedPostOnlyCheck, 27 | 28 | CASE WHEN 29 | ( 30 | SELECT TOP 1 PrgPayGroup 31 | FROM PayReg 32 | WHERE PrgPayGroup = @PayGroup AND 33 | PrgPerControl = @PerControl AND 34 | PrgRecordCreationSource <> 'E' 35 | ) 36 | IS NULL THEN 0 ELSE 1 END AS HasPostCheckHistory 37 | END 38 | -------------------------------------------------------------------------------- /chapter4/bankService/Account.java: -------------------------------------------------------------------------------- 1 | package bankService; 2 | import bankService.exceptions.*; 3 | 4 | /** 5 | * Abstracts the general concepts of a bank account. 6 | * @author Tariq King 7 | */ 8 | public abstract class Account { 9 | 10 | protected long accountNumber; 11 | protected double balance; 12 | protected Customer owner; 13 | 14 | public Account(Customer owner, double balance, long accountNumber) { 15 | this.owner = owner; 16 | this.balance = balance; 17 | this.accountNumber = accountNumber; 18 | } 19 | 20 | public Customer getOwner() { return this.owner; } 21 | 22 | public long getAccountNumber() { return this.accountNumber; } 23 | 24 | public double getBalance() { 25 | return this.balance; 26 | } 27 | 28 | public void deposit(double amount) throws InvalidAmountException { 29 | if (amount <= 0) { 30 | throw new InvalidAmountException(); 31 | } 32 | else { 33 | this.balance = this.balance+amount; 34 | } 35 | } 36 | 37 | public abstract void withdraw(double amount) throws InsufficientFundsException; 38 | 39 | } -------------------------------------------------------------------------------- /chapter5/bankService/Account.java: -------------------------------------------------------------------------------- 1 | package bankService; 2 | import bankService.exceptions.*; 3 | 4 | /** 5 | * Abstracts the general concepts of a bank account. 6 | * @author Tariq King 7 | */ 8 | public abstract class Account { 9 | 10 | protected long accountNumber; 11 | protected double balance; 12 | protected Customer owner; 13 | 14 | public Account(Customer owner, double balance, long accountNumber) { 15 | this.owner = owner; 16 | this.balance = balance; 17 | this.accountNumber = accountNumber; 18 | } 19 | 20 | public Customer getOwner() { return this.owner; } 21 | 22 | public long getAccountNumber() { return this.accountNumber; } 23 | 24 | public double getBalance() { 25 | return this.balance; 26 | } 27 | 28 | public void deposit(double amount) throws InvalidAmountException { 29 | if (amount <= 0) { 30 | throw new InvalidAmountException(); 31 | } 32 | else { 33 | this.balance = this.balance+amount; 34 | } 35 | } 36 | 37 | public abstract void withdraw(double amount) throws InsufficientFundsException; 38 | 39 | } -------------------------------------------------------------------------------- /chapter6/lib/RatingScaleLevelsValidator.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A validation helper for performance review rating scales. 3 | */ 4 | function RatingScaleLevelsValidator() { 5 | this.validate = function (levels) { 6 | this.validateAllLevelsHaveRating(levels); 7 | this.validateRangesAreContiguous(levels); 8 | }; 9 | 10 | /** 11 | * Validate that all rating levels have an associated rating code. 12 | */ 13 | this.validateAllLevelsHaveRating = function (levels) { 14 | // Iterate through each level in the levels collection passed in. 15 | $(levels).each(function () { 16 | 17 | // Retrieve this level's rating code. 18 | if (this.getRating() === "") { 19 | this.markRatingWithError(); 20 | } 21 | }); 22 | }; 23 | 24 | /** 25 | * Validate that all rating levels are contiguous. 26 | */ 27 | this.validateRangesAreContiguous = function (levels) { 28 | log.clearMessageNow(lstrRangeMustBeContiguous); 29 | 30 | for (i = 1; i < levels.length; i++) { 31 | var previousLevel = levels[i - 1]; 32 | var currentLevel = levels[i]; 33 | var previousMaxToCurrentMinDelta = 34 | currentLevel.getMinimumRange() - previousLevel.getMaximumRange(); 35 | 36 | if (previousMaxToCurrentMinDelta.toFixed(2) != 0.01) { 37 | log.add(lstrRangeMustBeContiguous); 38 | previousLevel.markMaximumRangeWithError(); 39 | currentLevel.markMinimumRangeWithError(); 40 | } 41 | } 42 | }; 43 | } 44 | 45 | module.exports = RatingScaleLevelsValidator; -------------------------------------------------------------------------------- /chapter6/sql/TestUndoOpenValidationSp.sql: -------------------------------------------------------------------------------- 1 | -- Create a new suite of tests. 2 | EXEC tSQLt.NewTestClass 'testValidateUndoOpen'; 3 | GO 4 | 5 | -- Execute the suite of tests. 6 | EXEC tSQLt.Run 'testValidateUndoOpen'; 7 | 8 | -- Execute all tests. 9 | tSQLt.RunAll 10 | 11 | -- Create a new test belonging to the `testValidateUndoOpen` suite. 12 | CREATE PROCEDURE testValidateUndoOpen.[test paygroup has printed check within a specified pay period] 13 | AS 14 | BEGIN 15 | 16 | /** 17 | * A payroll may not be un-opened if there is a printed post-only check. 18 | * Scenario: 19 | * 1. Given an existing payroll session that has been previously opened 20 | * 2. And a printed post-only check has been processed as part of the session 21 | * 3. When I invoke the payroll undo open validation 22 | * 4. Then a printed post-only check is found and reported by the validation procedure 23 | */ 24 | 25 | IF OBJECT_ID('actual') IS NOT NULL DROP TABLE actual; 26 | IF OBJECT_ID('expected') IS NOT NULL DROP TABLE expected; 27 | 28 | -- Arrange. 29 | EXEC tSQLt.FakeTable 'dbo.M_Batch' 30 | INSERT INTO dbo.M_Batch(MbtPayGroup, MbtPerControl, MbtPrinted, MbtPostOnly) VALUES ('ABC', '201502251', 'Y', 'N') 31 | CREATE TABLE actual (HasPrintedPostOnlyCheck bit, HasPostCheckHistory bit) 32 | CREATE TABLE expected (HasPrintedPostOnlyCheck bit, HasPostCheckHistory bit) 33 | 34 | -- Act. 35 | INSERT actual EXEC dbo.ValidateUndoOpen 'ABC', '201502251' 36 | 37 | -- Assert. 38 | INSERT expected (HasPrintedPostOnlyCheck, HasPostCheckHistory) VALUES (1, 0) 39 | EXEC tSQLt.AssertEqualsTable 'expected', 'actual'; 40 | 41 | END 42 | GO -------------------------------------------------------------------------------- /chapter4/bankService/SavingsAccount.java: -------------------------------------------------------------------------------- 1 | package bankService; 2 | 3 | import bankService.exceptions.InsufficientFundsException; 4 | import bankService.exceptions.InvalidAmountException; 5 | 6 | /** 7 | * Specialized bank account on which interest can be earned. 8 | * @author Tariq King 9 | */ 10 | public class SavingsAccount extends Account { 11 | 12 | private double annualInterestRate; 13 | private final double defaultAnnualInterestRate = 0.0005; 14 | private double unpaidInterest; 15 | 16 | public SavingsAccount(Customer owner, double startBalance, long accountNumber) { 17 | super(owner, startBalance, accountNumber); 18 | this.annualInterestRate = defaultAnnualInterestRate; 19 | this.unpaidInterest = 0.0; 20 | } 21 | 22 | @Override 23 | public void withdraw(double amount) throws InsufficientFundsException { 24 | if (amount > this.balance) { 25 | throw new InsufficientFundsException(); 26 | } 27 | else { 28 | this.balance = this.balance - amount; 29 | } 30 | } 31 | 32 | public void calculateUnpaidInterest() 33 | { 34 | unpaidInterest = unpaidInterest + this.balance * annualInterestRate; 35 | } 36 | 37 | public double getUnpaidInterest() { return unpaidInterest; } 38 | 39 | public void payInterest() 40 | { 41 | try { 42 | deposit(unpaidInterest); 43 | } catch (InvalidAmountException e) { 44 | e.printStackTrace(); 45 | } 46 | } 47 | 48 | public double getAnnualInterestRate() { 49 | return annualInterestRate; 50 | } 51 | 52 | public void setAnnualInterestRate(double annualInterestRate) 53 | { 54 | this.annualInterestRate = annualInterestRate; 55 | } 56 | } -------------------------------------------------------------------------------- /chapter5/bankService/SavingsAccount.java: -------------------------------------------------------------------------------- 1 | package bankService; 2 | 3 | import bankService.exceptions.InsufficientFundsException; 4 | import bankService.exceptions.InvalidAmountException; 5 | 6 | /** 7 | * Specialized bank account on which interest can be earned. 8 | * @author Tariq King 9 | */ 10 | public class SavingsAccount extends Account { 11 | 12 | private double annualInterestRate; 13 | private final double defaultAnnualInterestRate = 0.0005; 14 | private double unpaidInterest; 15 | 16 | public SavingsAccount(Customer owner, double startBalance, long accountNumber) { 17 | super(owner, startBalance, accountNumber); 18 | this.annualInterestRate = defaultAnnualInterestRate; 19 | this.unpaidInterest = 0.0; 20 | } 21 | 22 | @Override 23 | public void withdraw(double amount) throws InsufficientFundsException { 24 | if (amount > this.balance) { 25 | throw new InsufficientFundsException(); 26 | } 27 | else { 28 | this.balance = this.balance - amount; 29 | } 30 | } 31 | 32 | public void calculateUnpaidInterest() 33 | { 34 | unpaidInterest = unpaidInterest + this.balance * annualInterestRate; 35 | } 36 | 37 | public double getUnpaidInterest() { return unpaidInterest; } 38 | 39 | public void payInterest() 40 | { 41 | try { 42 | deposit(unpaidInterest); 43 | } catch (InvalidAmountException e) { 44 | e.printStackTrace(); 45 | } 46 | } 47 | 48 | public double getAnnualInterestRate() { 49 | return annualInterestRate; 50 | } 51 | 52 | public void setAnnualInterestRate(double annualInterestRate) 53 | { 54 | this.annualInterestRate = annualInterestRate; 55 | } 56 | } -------------------------------------------------------------------------------- /chapter4/bankService/Banking.java: -------------------------------------------------------------------------------- 1 | package bankService; 2 | 3 | import notificationService.Notification; 4 | import java.util.ArrayList; 5 | 6 | /** 7 | * Interface specifying banking capabilities such as creating and accessing customer accounts. 8 | * @author Tariq King 9 | */ 10 | public interface Banking { 11 | /** 12 | * @return name of the bank. 13 | */ 14 | public String getName(); 15 | 16 | /** 17 | * @return number used to direct data or documents to the bank (e.g., checks). 18 | */ 19 | public int getRoutingNumber(); 20 | 21 | /** 22 | * Create an account for a new or existing customer. 23 | * @param owner customer that will own the account being created. 24 | * @param startBalance initial balance of the account. 25 | * @param accountType type of the account e.g., checking, savings. 26 | * @return true if the account creation is successful, false otherwise. 27 | */ 28 | public boolean createAccount(Customer owner, double startBalance, AccountType accountType); 29 | 30 | /** 31 | * @return a list of bank accounts stored in the bank 32 | */ 33 | public ArrayList getAccounts(); 34 | 35 | /** 36 | * Connect to a specified notification service. 37 | * @param notificationService the notification service being connected to (e.g., e-mail, text message). 38 | */ 39 | public void connectToNotificationService(Notification notificationService); 40 | 41 | /** 42 | * Disconnects from the currently connected notification service. 43 | */ 44 | public void disconnectFromNotificationService(); 45 | 46 | /** 47 | * Enumerated type for referring to a specific type of account (e.g., checking or savings). 48 | */ 49 | public enum AccountType {Checking, Savings}; 50 | } -------------------------------------------------------------------------------- /chapter5/bankService/Banking.java: -------------------------------------------------------------------------------- 1 | package bankService; 2 | 3 | import notificationService.Notification; 4 | import java.util.ArrayList; 5 | 6 | /** 7 | * Interface specifying banking capabilities such as creating and accessing customer accounts. 8 | * @author Tariq King 9 | */ 10 | public interface Banking { 11 | /** 12 | * @return name of the bank. 13 | */ 14 | public String getName(); 15 | 16 | /** 17 | * @return number used to direct data or documents to the bank (e.g., checks). 18 | */ 19 | public int getRoutingNumber(); 20 | 21 | /** 22 | * Create an account for a new or existing customer. 23 | * @param owner customer that will own the account being created. 24 | * @param startBalance initial balance of the account. 25 | * @param accountType type of the account e.g., checking, savings. 26 | * @return true if the account creation is successful, false otherwise. 27 | */ 28 | public boolean createAccount(Customer owner, double startBalance, AccountType accountType); 29 | 30 | /** 31 | * @return a list of bank accounts stored in the bank 32 | */ 33 | public ArrayList getAccounts(); 34 | 35 | /** 36 | * Connect to a specified notification service. 37 | * @param notificationService the notification service being connected to (e.g., e-mail, text message). 38 | */ 39 | public void connectToNotificationService(Notification notificationService); 40 | 41 | /** 42 | * Disconnects from the currently connected notification service. 43 | */ 44 | public void disconnectFromNotificationService(); 45 | 46 | /** 47 | * Enumerated type for referring to a specific type of account (e.g., checking or savings). 48 | */ 49 | public enum AccountType {Checking, Savings}; 50 | } -------------------------------------------------------------------------------- /chapter4/CustomerTest.java: -------------------------------------------------------------------------------- 1 | import org.testng.annotations.Test; 2 | 3 | import static org.testng.Assert.*; 4 | 5 | public class CustomerTest { 6 | 7 | /** 8 | * The system should be able to store information on a new customer using valid data. 9 | * Scenario: 10 | * 1. Given I create a new customer named Mickey Mouse 11 | * 2. When I initialize the customer object with valid details. 12 | * 3. Then Mickey's information should be stored in the system. 13 | */ 14 | @Test 15 | public void creatingCustomerWithValidData_StoresSpecifiedData() { 16 | 17 | // Given and When 18 | Customer customer = new Customer("Mickey Mouse", "Disneyland", "Mickey@Disneyland.com"); 19 | 20 | // Then 21 | assertNotNull(customer); 22 | assertEquals(customer.getName(), "Mickey Mouse"); 23 | assertEquals(customer.getAddress(), "Disneyland"); 24 | assertEquals(customer.getEmail(), "Mickey@Disneyland.com"); 25 | } 26 | 27 | /** 28 | * The system should be able to update customer information using valid data. 29 | * Scenario: 30 | * 1. Given I create a new customer named Mickey Mouse. 31 | * 2. When I update Mickey's customer information with Minnie's information. 32 | * 3. Then Minnie's information should be stored in the system. 33 | */ 34 | @Test 35 | public void updatingCustomerDataWithDifferentValidValues_StoresNewValues() { 36 | 37 | // Given 38 | Customer customer = new Customer("Mickey", "Disneyland", "Mickey@Disneyland.com"); 39 | 40 | // When 41 | customer.updateName("Minnie Mouse"); 42 | customer.updateAddress("Disney World"); 43 | customer.updateEmail("Minnie@Disneyworld.com"); 44 | 45 | // Then 46 | assertEquals(customer.getName(), "Minnie Mouse"); 47 | assertEquals(customer.getAddress(), "Disney World"); 48 | assertEquals(customer.getEmail(), "Minnie@Disneyworld.com"); 49 | 50 | } 51 | } -------------------------------------------------------------------------------- /chapter5/CustomerTest.java: -------------------------------------------------------------------------------- 1 | import org.testng.annotations.Test; 2 | 3 | import static org.testng.Assert.*; 4 | 5 | public class CustomerTest { 6 | 7 | /** 8 | * The system should be able to store information on a new customer using valid data. 9 | * Scenario: 10 | * 1. Given I create a new customer named Mickey Mouse 11 | * 2. When I initialize the customer object with valid details. 12 | * 3. Then Mickey's information should be stored in the system. 13 | */ 14 | @Test 15 | public void creatingCustomerWithValidData_StoresSpecifiedData() { 16 | 17 | // Given and When 18 | Customer customer = new Customer("Mickey Mouse", "Disneyland", "Mickey@Disneyland.com"); 19 | 20 | // Then 21 | assertNotNull(customer); 22 | assertEquals(customer.getName(), "Mickey Mouse"); 23 | assertEquals(customer.getAddress(), "Disneyland"); 24 | assertEquals(customer.getEmail(), "Mickey@Disneyland.com"); 25 | } 26 | 27 | /** 28 | * The system should be able to update customer information using valid data. 29 | * Scenario: 30 | * 1. Given I create a new customer named Mickey Mouse. 31 | * 2. When I update Mickey's customer information with Minnie's information. 32 | * 3. Then Minnie's information should be stored in the system. 33 | */ 34 | @Test 35 | public void updatingCustomerDataWithDifferentValidValues_StoresNewValues() { 36 | 37 | // Given 38 | Customer customer = new Customer("Mickey", "Disneyland", "Mickey@Disneyland.com"); 39 | 40 | // When 41 | customer.updateName("Minnie Mouse"); 42 | customer.updateAddress("Disney World"); 43 | customer.updateEmail("Minnie@Disneyworld.com"); 44 | 45 | // Then 46 | assertEquals(customer.getName(), "Minnie Mouse"); 47 | assertEquals(customer.getAddress(), "Disney World"); 48 | assertEquals(customer.getEmail(), "Minnie@Disneyworld.com"); 49 | 50 | } 51 | } -------------------------------------------------------------------------------- /chapter4/bankService/SavingsAccountTest.java: -------------------------------------------------------------------------------- 1 | package bankService; 2 | 3 | import bankService.exceptions.InsufficientFundsException; 4 | import org.testng.annotations.BeforeClass; 5 | import org.testng.annotations.BeforeMethod; 6 | import org.testng.annotations.DataProvider; 7 | import org.testng.annotations.Test; 8 | 9 | import static org.testng.Assert.*; 10 | 11 | public class SavingsAccountTest { 12 | 13 | Customer customer; 14 | SavingsAccount savings; 15 | 16 | @BeforeClass 17 | public void oneTimeSetup() { 18 | customer = new Customer ("Mickey Mouse", "Disneyland", "Mickey@disneyland.com"); 19 | } 20 | 21 | @BeforeMethod 22 | public void eachTimeSetup() { 23 | savings = new SavingsAccount(customer, 100.00, 123456789); 24 | } 25 | 26 | /** 27 | * Customers should be able to withdraw from their savings account. 28 | * Scenario: 29 | * 1. Given a customer's savings account with an initial balance of $100.00 30 | * 2. When I withdraw $60.00 from the account 31 | * 3. Then the new account balance is $40.00 32 | */ 33 | @Test(dataProvider ="ValidWithdrawDataProvider") 34 | public void withdrawingValidAmountFromSavingsAccount_DecreasesBalanceByAmount(double amount, double expectedBalance) throws InsufficientFundsException { 35 | // When 36 | savings.withdraw(amount); 37 | 38 | // Then 39 | assertEquals(savings.getBalance(), expectedBalance); 40 | } 41 | 42 | @DataProvider(name= "ValidWithdrawDataProvider") 43 | private Object[][] createValidWithdrawData() { 44 | return new Object[][] { 45 | {60.0, 40.0}, 46 | {100.0, 0.0}}; 47 | } 48 | 49 | /** 50 | * Customers should not be able to withdraw more than their available savings account balance 51 | * Scenario: 52 | * 1. Given a customer's savings account with an initial balance of $100.00 53 | * 2. When I attempt to withdraw $200.00 54 | * 3. Then an exception should occur indicating that there are insufficient funds in the account 55 | * 4. And the account balance should remain unchanged. 56 | */ 57 | @Test 58 | public void withdrawingAmountGreaterThanBalance_Throws_InsufficientFundsException() throws InsufficientFundsException { 59 | -------------------------------------------------------------------------------- /chapter6/_test_/RatingScaleLevelsValidator.test.js: -------------------------------------------------------------------------------- 1 | import RatingScaleLevelsValidator from '../lib/RatingScaleLevelsValidator'; 2 | 3 | describe("Validate all levels have ratings", function(){ 4 | var validator; 5 | 6 | var createLevel = function(ratingCode){ 7 | var level = new Object(); 8 | level.getRating = level.markRatingWithError = function() { } 9 | spyOn(level, "getRating").and.returnValue(ratingCode); 10 | spyOn(level, "markRatingWithError"); 11 | return level; 12 | } 13 | 14 | beforeEach(function(){ 15 | validator = new RatingScaleLevelsValidator(); 16 | }) 17 | 18 | /** 19 | * A single level with an assigned rating code should be considered valid. 20 | * Scenario: 21 | * 1. Given a set of rating levels with a single rating level 22 | * 2. And the rating level is assigned with a rating code of "ABC" 23 | * 3. When I validate the rating levels 24 | * 4. Then the rating level is considered valid and is not marked with an error 25 | */ 26 | it("Single level with defined rating should be valid", function(){ 27 | // Arrange. 28 | var levels = [] 29 | var level = createLevel("ABC"); 30 | levels.push(level); 31 | 32 | // Act. 33 | validator.validateAllLevelsHaveRating(levels); 34 | 35 | // Assert. 36 | expect(level.getRating).toHaveBeenCalled(); 37 | expect(level.markRatingWithError).not.toHaveBeenCalled(); 38 | }); 39 | 40 | /** 41 | * A single level with an empty rating code assignment should be considered invalid. 42 | * Scenario: 43 | * 1. Given a set of rating levels with a single rating level 44 | * 2. And the rating level is assigned with a rating code of "" 45 | * 3. When I validate the rating levels 46 | * 4. Then the rating level is considered invalid and is marked with an error 47 | */ 48 | it("Single level with empty rating should be invalid", function(){ 49 | // Arrange. 50 | var levels = [] 51 | var level = createLevel(""); 52 | levels.push(level); 53 | 54 | // Act. 55 | validator.validateAllLevelsHaveRating(levels); 56 | 57 | // Assert. 58 | expect(level.getRating).toHaveBeenCalled(); 59 | expect(level.markRatingWithError).toHaveBeenCalled(); 60 | }); 61 | }); -------------------------------------------------------------------------------- /chapter5/bankService/SavingsAccountTest.java: -------------------------------------------------------------------------------- 1 | package bankService; 2 | 3 | import bankService.exceptions.InsufficientFundsException; 4 | import org.testng.annotations.BeforeClass; 5 | import org.testng.annotations.BeforeMethod; 6 | import org.testng.annotations.DataProvider; 7 | import org.testng.annotations.Test; 8 | 9 | import static org.testng.Assert.*; 10 | 11 | public class SavingsAccountTest { 12 | 13 | Customer customer; 14 | SavingsAccount savings; 15 | 16 | @BeforeClass 17 | public void oneTimeSetup() { 18 | customer = new Customer ("Mickey Mouse", "Disneyland", "Mickey@disneyland.com"); 19 | } 20 | 21 | @BeforeMethod 22 | public void eachTimeSetup() { 23 | savings = new SavingsAccount(customer, 100.00, 123456789); 24 | } 25 | 26 | /** 27 | * Customers should be able to withdraw from their savings account. 28 | * Scenario: 29 | * 1. Given a customer's savings account with an initial balance of $100.00 30 | * 2. When I withdraw $60.00 from the account 31 | * 3. Then the new account balance is $40.00 32 | */ 33 | @Test(dataProvider ="ValidWithdrawDataProvider") 34 | public void withdrawingValidAmountFromSavingsAccount_DecreasesBalanceByAmount(double amount, double expectedBalance) throws InsufficientFundsException { 35 | // When 36 | savings.withdraw(amount); 37 | 38 | // Then 39 | assertEquals(savings.getBalance(), expectedBalance); 40 | } 41 | 42 | @DataProvider(name= "ValidWithdrawDataProvider") 43 | private Object[][] createValidWithdrawData() { 44 | return new Object[][] { 45 | {60.0, 40.0}, 46 | {100.0, 0.0}}; 47 | } 48 | 49 | /** 50 | * Customers should not be able to withdraw more than their available savings account balance 51 | * Scenario: 52 | * 1. Given a customer's savings account with an initial balance of $100.00 53 | * 2. When I attempt to withdraw $200.00 54 | * 3. Then an exception should occur indicating that there are insufficient funds in the account 55 | * 4. And the account balance should remain unchanged. 56 | */ 57 | @Test 58 | public void withdrawingAmountGreaterThanBalance_Throws_InsufficientFundsException() throws InsufficientFundsException { 59 | try { 60 | savings.withdraw(200.00); 61 | fail("Expected Insufficient Funds Exception but none is thrown"); 62 | } catch (InsufficientFundsException e){ 63 | // Then 64 | assertEquals(savings.getBalance(), 100.00); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /chapter4/bankApplication/Bank.java: -------------------------------------------------------------------------------- 1 | package bankApplication; 2 | 3 | import bankService.*; 4 | import notificationService.*; 5 | import static bankService.Banking.AccountType.*; 6 | 7 | /** 8 | * A commercial bank or credit union with a limited scope of services. 9 | * @author Tariq King 10 | */ 11 | public class Bank 12 | { 13 | private Banking bankService; 14 | private Notification notificationService; 15 | 16 | /** 17 | * Creates a new bank when provided with the required banking and notification services. 18 | * @param bankService service for holding customer information and performing bank transactions 19 | * @param notificationService service for notifying customers of account activity 20 | */ 21 | public Bank(Banking bankService, Notification notificationService) 22 | { 23 | this.bankService = bankService; 24 | this.bankService.connectToNotificationService(notificationService); 25 | } 26 | 27 | /** 28 | * Access the Banking Service. 29 | * @return A reference to the banking service for this bank 30 | */ 31 | public Banking getBankService() { 32 | return this.bankService; 33 | } 34 | /** 35 | * Access the Notification Service. 36 | * @return A reference to the notification service for this bank 37 | */ 38 | public Notification getNotificationService() { return this.notificationService; } 39 | 40 | /** 41 | * Driver for the Bank Application. 42 | */ 43 | public static void main(String [] args) { 44 | 45 | // Initialize required services 46 | Banking bankService = new BankService("Partners Federal Credit Union", 256074974, 500135210, 100769310); 47 | Notification notificationService = new EmailService(); 48 | 49 | // Create a new bank and the first customer 50 | Bank bank = new Bank(bankService, notificationService); 51 | Customer customer = new Customer("Mickey Mouse", "Disneyland", "Mickey@Disneyland.com"); 52 | 53 | // Create a checking and savings accounts for the customer 54 | bank.getBankService().createAccount(customer, 2000.0, Checking); 55 | bank.getBankService().createAccount(customer, 10000.0, Savings); 56 | bank.getBankService().createAccount(customer, 10000.0, Savings); 57 | 58 | // Print some information on the bank 59 | System.out.println("Bank Name: " + bank.getBankService().getName()); 60 | System.out.println("Routing Number: " + bank.getBankService().getRoutingNumber()); 61 | System.out.println("Total Accounts: " + bank.getBankService().getAccounts().size()); 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /chapter5/bankApplication/Bank.java: -------------------------------------------------------------------------------- 1 | package bankApplication; 2 | 3 | import bankService.*; 4 | import notificationService.*; 5 | import static bankService.Banking.AccountType.*; 6 | 7 | /** 8 | * A commercial bank or credit union with a limited scope of services. 9 | * @author Tariq King 10 | */ 11 | public class Bank 12 | { 13 | private Banking bankService; 14 | private Notification notificationService; 15 | 16 | /** 17 | * Creates a new bank when provided with the required banking and notification services. 18 | * @param bankService service for holding customer information and performing bank transactions 19 | * @param notificationService service for notifying customers of account activity 20 | */ 21 | public Bank(Banking bankService, Notification notificationService) 22 | { 23 | this.bankService = bankService; 24 | this.bankService.connectToNotificationService(notificationService); 25 | } 26 | 27 | /** 28 | * Access the Banking Service. 29 | * @return A reference to the banking service for this bank 30 | */ 31 | public Banking getBankService() { 32 | return this.bankService; 33 | } 34 | /** 35 | * Access the Notification Service. 36 | * @return A reference to the notification service for this bank 37 | */ 38 | public Notification getNotificationService() { return this.notificationService; } 39 | 40 | /** 41 | * Driver for the Bank Application. 42 | */ 43 | public static void main(String [] args) { 44 | 45 | // Initialize required services 46 | Banking bankService = new BankService("Partners Federal Credit Union", 256074974, 500135210, 100769310); 47 | Notification notificationService = new EmailService(); 48 | 49 | // Create a new bank and the first customer 50 | Bank bank = new Bank(bankService, notificationService); 51 | Customer customer = new Customer("Mickey Mouse", "Disneyland", "Mickey@Disneyland.com"); 52 | 53 | // Create a checking and savings accounts for the customer 54 | bank.getBankService().createAccount(customer, 2000.0, Checking); 55 | bank.getBankService().createAccount(customer, 10000.0, Savings); 56 | bank.getBankService().createAccount(customer, 10000.0, Savings); 57 | 58 | // Print some information on the bank 59 | System.out.println("Bank Name: " + bank.getBankService().getName()); 60 | System.out.println("Routing Number: " + bank.getBankService().getRoutingNumber()); 61 | System.out.println("Total Accounts: " + bank.getBankService().getAccounts().size()); 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /chapter4/bankService/CheckingAccountTest.java: -------------------------------------------------------------------------------- 1 | package bankService; 2 | 3 | import notificationService.EmailService; 4 | import org.mockito.Mock; 5 | import org.mockito.MockitoAnnotations; 6 | import org.mockito.Spy; 7 | import org.testng.annotations.BeforeClass; 8 | import org.testng.annotations.BeforeMethod; 9 | import org.testng.annotations.Test; 10 | 11 | import static org.mockito.Matchers.contains; 12 | import static org.mockito.Matchers.eq; 13 | import static org.mockito.Mockito.verify; 14 | import static org.mockito.Mockito.when; 15 | import static org.testng.Assert.*; 16 | 17 | public class CheckingAccountTest { 18 | 19 | Customer customer; 20 | CheckingAccount checking; 21 | 22 | @BeforeClass 23 | public void oneTimeSetup() { 24 | customer = new Customer ("Mickey Mouse", "Disneyland", "Mickey@disneyland.com"); 25 | } 26 | 27 | @BeforeMethod 28 | public void eachTimeSetup() { 29 | checking = new CheckingAccount(customer, 250.00, 987654321); 30 | MockitoAnnotations.initMocks(this); 31 | } 32 | 33 | @Mock 34 | Check mockCheck; 35 | 36 | /** 37 | * Customers should be able to process a valid check on a checking account with sufficient funds 38 | * Scenario: 39 | * 1. Given a customer's checking account with an initial balance of $250.00 40 | * 2. When I process a check for $100.00 41 | * 3. Then the new account balance should be $150.00 42 | */ 43 | @Test 44 | public void processingCheckWithSufficientFunds_DecreasesBalanceByAmount() { 45 | // Given 46 | when(mockCheck.getAmount()).thenReturn(100.00); 47 | when(mockCheck.getCheckNumber()).thenReturn(4321); 48 | 49 | // When 50 | checking.processCheck(mockCheck); 51 | 52 | // Then 53 | assertEquals(checking.getBalance(), 150.00); 54 | } 55 | 56 | @Spy 57 | EmailService spiedEmailService = new EmailService(); 58 | 59 | /** 60 | * Customers should be able to receive notifications that a check has been processed. 61 | * Scenario: 62 | * 1. Given I enable E-mail notifications on the checking account 63 | * 2. And I have a valid check #4321 for amount $100.00 64 | * 3. When I process check #4321 65 | * 4. Then the transaction notification should be sent via e-mail 66 | * 5. And the account balance should be $150.00 67 | */ 68 | @Test 69 | public void processingCheckWithNotificationsEnabled_DecreaseBalanceAndSendsMessage() { 70 | // Given 71 | checking.enableNotifications(spiedEmailService); 72 | when(mockCheck.getCheckNumber()).thenReturn(4321); 73 | when(mockCheck.getAmount()).thenReturn(100.0); 74 | 75 | // When 76 | checking.processCheck(mockCheck); 77 | 78 | // Then 79 | verify(spiedEmailService).notify(contains("Check #4321"), eq(checking.getOwner().getEmail())); 80 | assertEquals(checking.getBalance(), 150.00); 81 | } 82 | } -------------------------------------------------------------------------------- /chapter5/bankService/CheckingAccountTest.java: -------------------------------------------------------------------------------- 1 | package bankService; 2 | 3 | import notificationService.EmailService; 4 | import org.mockito.Mock; 5 | import org.mockito.MockitoAnnotations; 6 | import org.mockito.Spy; 7 | import org.testng.annotations.BeforeClass; 8 | import org.testng.annotations.BeforeMethod; 9 | import org.testng.annotations.Test; 10 | 11 | import static org.mockito.Matchers.contains; 12 | import static org.mockito.Matchers.eq; 13 | import static org.mockito.Mockito.verify; 14 | import static org.mockito.Mockito.when; 15 | import static org.testng.Assert.*; 16 | 17 | public class CheckingAccountTest { 18 | 19 | Customer customer; 20 | CheckingAccount checking; 21 | 22 | @BeforeClass 23 | public void oneTimeSetup() { 24 | customer = new Customer ("Mickey Mouse", "Disneyland", "Mickey@disneyland.com"); 25 | } 26 | 27 | @BeforeMethod 28 | public void eachTimeSetup() { 29 | checking = new CheckingAccount(customer, 250.00, 987654321); 30 | MockitoAnnotations.initMocks(this); 31 | } 32 | 33 | @Mock 34 | Check mockCheck; 35 | 36 | /** 37 | * Customers should be able to process a valid check on a checking account with sufficient funds 38 | * Scenario: 39 | * 1. Given a customer's checking account with an initial balance of $250.00 40 | * 2. When I process a check for $100.00 41 | * 3. Then the new account balance should be $150.00 42 | */ 43 | @Test 44 | public void processingCheckWithSufficientFunds_DecreasesBalanceByAmount() { 45 | // Given 46 | when(mockCheck.getAmount()).thenReturn(100.00); 47 | when(mockCheck.getCheckNumber()).thenReturn(4321); 48 | 49 | // When 50 | checking.processCheck(mockCheck); 51 | 52 | // Then 53 | assertEquals(checking.getBalance(), 150.00); 54 | } 55 | 56 | @Spy 57 | EmailService spiedEmailService = new EmailService(); 58 | 59 | /** 60 | * Customers should be able to receive notifications that a check has been processed. 61 | * Scenario: 62 | * 1. Given I enable E-mail notifications on the checking account 63 | * 2. And I have a valid check #4321 for amount $100.00 64 | * 3. When I process check #4321 65 | * 4. Then the transaction notification should be sent via e-mail 66 | * 5. And the account balance should be $150.00 67 | */ 68 | @Test 69 | public void processingCheckWithNotificationsEnabled_DecreaseBalanceAndSendsMessage() { 70 | // Given 71 | checking.enableNotifications(spiedEmailService); 72 | when(mockCheck.getCheckNumber()).thenReturn(4321); 73 | when(mockCheck.getAmount()).thenReturn(100.0); 74 | 75 | // When 76 | checking.processCheck(mockCheck); 77 | 78 | // Then 79 | verify(spiedEmailService).notify(contains("Check #4321"), eq(checking.getOwner().getEmail())); 80 | assertEquals(checking.getBalance(), 150.00); 81 | } 82 | } -------------------------------------------------------------------------------- /chapter4/bankService/CheckingAccount.java: -------------------------------------------------------------------------------- 1 | package bankService; 2 | 3 | import bankService.exceptions.InsufficientFundsException; 4 | import bankService.exceptions.InvalidAmountException; 5 | import notificationService.Notification; 6 | 7 | /** 8 | * Specialized bank account on which checks can be processed. 9 | * @author Tariq King 10 | */ 11 | public class CheckingAccount extends Account { 12 | 13 | private double minBalance; 14 | private double overdraftLimit; 15 | private double overdraftFee; 16 | private double serviceFee; 17 | private boolean isOverDrawn; 18 | private boolean droppedBelowMinBalance; 19 | private boolean notificationsEnabled; 20 | private Notification notificationService; 21 | 22 | public CheckingAccount(Customer owner, double startBalance, long accountNumber) { 23 | super(owner, startBalance, accountNumber); 24 | this.minBalance=1500.0; 25 | this.overdraftLimit=0.0; 26 | this.overdraftFee=30.0; 27 | this.serviceFee=12.0; 28 | this.isOverDrawn=false; 29 | this.droppedBelowMinBalance =false; 30 | this.notificationsEnabled=false; 31 | this.notificationService=null; 32 | } 33 | 34 | @Override 35 | public void withdraw(double amount) throws InsufficientFundsException { 36 | if(amount <= this.balance+overdraftLimit) { 37 | this.balance = this.balance - amount; 38 | updateAccountStatus(); 39 | if (isOverDrawn) { 40 | this.balance = this.balance - overdraftFee; 41 | } 42 | } 43 | else throw new InsufficientFundsException(); 44 | } 45 | 46 | private void updateAccountStatus() 47 | { 48 | this.isOverDrawn = this.balance < 0; 49 | if (this.balance < minBalance) { droppedBelowMinBalance = true; } 50 | } 51 | 52 | @Override 53 | public void deposit(double amount) throws InvalidAmountException { 54 | super.deposit(amount); 55 | updateAccountStatus(); 56 | } 57 | 58 | public void deductFees() { 59 | updateAccountStatus(); 60 | if (this.droppedBelowMinBalance) { 61 | this.balance = this.balance - this.serviceFee; 62 | this.droppedBelowMinBalance = false; 63 | } 64 | } 65 | 66 | public void processCheck(Check checkToProcess) 67 | { 68 | try { 69 | withdraw(checkToProcess.getAmount()); 70 | if (notificationsEnabled) { 71 | notificationService.notify("Processed Check #" + checkToProcess.getCheckNumber() 72 | + " in the amount of $" + checkToProcess.getAmount() + ".", owner.getEmail()); 73 | } 74 | } catch (InsufficientFundsException e) { 75 | e.printStackTrace(); 76 | } 77 | } 78 | 79 | public void enableNotifications(Notification notificationService) { 80 | notificationsEnabled=true; 81 | this.notificationService = notificationService; 82 | } 83 | 84 | public void disableNotifications() { 85 | notificationsEnabled=false; 86 | this.notificationService=null; 87 | } 88 | } -------------------------------------------------------------------------------- /chapter5/bankService/CheckingAccount.java: -------------------------------------------------------------------------------- 1 | package bankService; 2 | 3 | import bankService.exceptions.InsufficientFundsException; 4 | import bankService.exceptions.InvalidAmountException; 5 | import notificationService.Notification; 6 | 7 | /** 8 | * Specialized bank account on which checks can be processed. 9 | * @author Tariq King 10 | */ 11 | public class CheckingAccount extends Account { 12 | 13 | private double minBalance; 14 | private double overdraftLimit; 15 | private double overdraftFee; 16 | private double serviceFee; 17 | private boolean isOverDrawn; 18 | private boolean droppedBelowMinBalance; 19 | private boolean notificationsEnabled; 20 | private Notification notificationService; 21 | 22 | public CheckingAccount(Customer owner, double startBalance, long accountNumber) { 23 | super(owner, startBalance, accountNumber); 24 | this.minBalance=1500.0; 25 | this.overdraftLimit=0.0; 26 | this.overdraftFee=30.0; 27 | this.serviceFee=12.0; 28 | this.isOverDrawn=false; 29 | this.droppedBelowMinBalance =false; 30 | this.notificationsEnabled=false; 31 | this.notificationService=null; 32 | } 33 | 34 | @Override 35 | public void withdraw(double amount) throws InsufficientFundsException { 36 | if(amount <= this.balance+overdraftLimit) { 37 | this.balance = this.balance - amount; 38 | updateAccountStatus(); 39 | if (isOverDrawn) { 40 | this.balance = this.balance - overdraftFee; 41 | } 42 | } 43 | else throw new InsufficientFundsException(); 44 | } 45 | 46 | private void updateAccountStatus() 47 | { 48 | this.isOverDrawn = this.balance < 0; 49 | if (this.balance < minBalance) { droppedBelowMinBalance = true; } 50 | } 51 | 52 | @Override 53 | public void deposit(double amount) throws InvalidAmountException { 54 | super.deposit(amount); 55 | updateAccountStatus(); 56 | } 57 | 58 | public void deductFees() { 59 | updateAccountStatus(); 60 | if (this.droppedBelowMinBalance) { 61 | this.balance = this.balance - this.serviceFee; 62 | this.droppedBelowMinBalance = false; 63 | } 64 | } 65 | 66 | public void processCheck(Check checkToProcess) 67 | { 68 | try { 69 | withdraw(checkToProcess.getAmount()); 70 | if (notificationsEnabled) { 71 | notificationService.notify("Processed Check #" + checkToProcess.getCheckNumber() 72 | + " in the amount of $" + checkToProcess.getAmount() + ".", owner.getEmail()); 73 | } 74 | } catch (InsufficientFundsException e) { 75 | e.printStackTrace(); 76 | } 77 | } 78 | 79 | public void enableNotifications(Notification notificationService) { 80 | notificationsEnabled=true; 81 | this.notificationService = notificationService; 82 | } 83 | 84 | public void disableNotifications() { 85 | notificationsEnabled=false; 86 | this.notificationService=null; 87 | } 88 | } -------------------------------------------------------------------------------- /chapter4/bankService/BankService.java: -------------------------------------------------------------------------------- 1 | package bankService; 2 | 3 | import notificationService.Notification; 4 | import java.util.ArrayList; 5 | 6 | /** 7 | * Implements functionality for performing bank transactions and retrieving information on the bank. Interacts with a notification service for sending messages to customers. 8 | * @author Tariq King 9 | */ 10 | public class BankService implements Banking { 11 | 12 | private String name; 13 | private int routingNumber; 14 | private static long checkingStartNumber; 15 | private static long savingsStartNumber; 16 | private ArrayList accounts; 17 | private Notification notificationService; 18 | 19 | /** 20 | * Creates and initializes a new bank service. 21 | * @param name name of the bank. 22 | * @param routingNumber number used to direct data or documents to the bank. 23 | * @param checkingStartNumber number used to start the sequence of checking accounts that can be created. 24 | * @param savingsStartNumber number used to start the sequence of savings accounts that can be created. 25 | */ 26 | public BankService(String name, int routingNumber, long checkingStartNumber, long savingsStartNumber) { 27 | this.name = name; 28 | this.routingNumber = routingNumber; 29 | accounts = new ArrayList(); 30 | this.notificationService = notificationService; 31 | BankService.checkingStartNumber = checkingStartNumber; 32 | BankService.savingsStartNumber = savingsStartNumber; 33 | this.notificationService = null; 34 | } 35 | 36 | /** 37 | * @return name of the bank. 38 | */ 39 | public String getName() { 40 | return this.name; 41 | } 42 | 43 | /** 44 | * @return number used to direct data or documents to the bank (e.g., checks). 45 | */ 46 | public int getRoutingNumber() { return this.routingNumber; } 47 | 48 | /** 49 | * @return a list of bank accounts stored in the bank. 50 | */ 51 | public ArrayList getAccounts() { return accounts; } 52 | 53 | /** 54 | * Create an account for a new or existing customer. 55 | * @param owner customer that will own the account being created. 56 | * @param startBalance initial balance of the account. 57 | * @param accountType type of the account e.g., checking, savings. 58 | * @return true if the account creation is successful, false otherwise. 59 | */ 60 | @Override 61 | public boolean createAccount(Customer owner, double startBalance, AccountType accountType) { 62 | if(accountType == AccountType.Checking) { 63 | accounts.add(new CheckingAccount(owner, startBalance, checkingStartNumber)); 64 | checkingStartNumber++; 65 | return true; 66 | } 67 | else if (accountType == AccountType.Savings) { 68 | accounts.add(new SavingsAccount(owner, startBalance, savingsStartNumber)); 69 | savingsStartNumber++; 70 | return true; 71 | } 72 | return false; 73 | } 74 | 75 | /** 76 | * Connect to a specified notification service. 77 | * @param notificationService the notification service being connected to (e.g., e-mail, text message). 78 | */ 79 | public void connectToNotificationService(Notification notificationService) { 80 | this.notificationService = notificationService; 81 | notificationService.connect(); 82 | } 83 | 84 | /** 85 | * Disconnects from the currently connected notification service. 86 | */ 87 | public void disconnectFromNotificationService() { 88 | notificationService.disconnect(); 89 | this.notificationService = null; 90 | } 91 | } -------------------------------------------------------------------------------- /chapter5/bankService/BankService.java: -------------------------------------------------------------------------------- 1 | package bankService; 2 | 3 | import notificationService.Notification; 4 | import java.util.ArrayList; 5 | 6 | /** 7 | * Implements functionality for performing bank transactions and retrieving information on the bank. Interacts with a notification service for sending messages to customers. 8 | * @author Tariq King 9 | */ 10 | public class BankService implements Banking { 11 | 12 | private String name; 13 | private int routingNumber; 14 | private static long checkingStartNumber; 15 | private static long savingsStartNumber; 16 | private ArrayList accounts; 17 | private Notification notificationService; 18 | 19 | /** 20 | * Creates and initializes a new bank service. 21 | * @param name name of the bank. 22 | * @param routingNumber number used to direct data or documents to the bank. 23 | * @param checkingStartNumber number used to start the sequence of checking accounts that can be created. 24 | * @param savingsStartNumber number used to start the sequence of savings accounts that can be created. 25 | */ 26 | public BankService(String name, int routingNumber, long checkingStartNumber, long savingsStartNumber) { 27 | this.name = name; 28 | this.routingNumber = routingNumber; 29 | accounts = new ArrayList(); 30 | this.notificationService = notificationService; 31 | BankService.checkingStartNumber = checkingStartNumber; 32 | BankService.savingsStartNumber = savingsStartNumber; 33 | this.notificationService = null; 34 | } 35 | 36 | /** 37 | * @return name of the bank. 38 | */ 39 | public String getName() { 40 | return this.name; 41 | } 42 | 43 | /** 44 | * @return number used to direct data or documents to the bank (e.g., checks). 45 | */ 46 | public int getRoutingNumber() { return this.routingNumber; } 47 | 48 | /** 49 | * @return a list of bank accounts stored in the bank. 50 | */ 51 | public ArrayList getAccounts() { return accounts; } 52 | 53 | /** 54 | * Create an account for a new or existing customer. 55 | * @param owner customer that will own the account being created. 56 | * @param startBalance initial balance of the account. 57 | * @param accountType type of the account e.g., checking, savings. 58 | * @return true if the account creation is successful, false otherwise. 59 | */ 60 | @Override 61 | public boolean createAccount(Customer owner, double startBalance, AccountType accountType) { 62 | if(accountType == AccountType.Checking) { 63 | accounts.add(new CheckingAccount(owner, startBalance, checkingStartNumber)); 64 | checkingStartNumber++; 65 | return true; 66 | } 67 | else if (accountType == AccountType.Savings) { 68 | accounts.add(new SavingsAccount(owner, startBalance, savingsStartNumber)); 69 | savingsStartNumber++; 70 | return true; 71 | } 72 | return false; 73 | } 74 | 75 | /** 76 | * Connect to a specified notification service. 77 | * @param notificationService the notification service being connected to (e.g., e-mail, text message). 78 | */ 79 | public void connectToNotificationService(Notification notificationService) { 80 | this.notificationService = notificationService; 81 | notificationService.connect(); 82 | } 83 | 84 | /** 85 | * Disconnects from the currently connected notification service. 86 | */ 87 | public void disconnectFromNotificationService() { 88 | notificationService.disconnect(); 89 | this.notificationService = null; 90 | } 91 | } --------------------------------------------------------------------------------