fixed the tests

This commit is contained in:
Tom Hombergs
2019-08-17 09:07:36 +02:00
parent cc2237590a
commit eab6af3485
10 changed files with 96 additions and 57 deletions

View File

@@ -47,4 +47,14 @@ class AccountMapper {
return new ActivityWindow(mappedActivities);
}
ActivityJpaEntity mapToJpaEntity(Activity activity) {
return new ActivityJpaEntity(
activity.getId() == null ? null : activity.getId().getValue(),
activity.getTimestamp(),
activity.getOwnerAccountId().getValue(),
activity.getSourceAccountId().getValue(),
activity.getTargetAccountId().getValue(),
activity.getMoney().getAmount().longValue());
}
}

View File

@@ -62,18 +62,9 @@ class AccountPersistenceAdapter implements
public void updateActivities(Account account) {
for (Activity activity : account.getActivityWindow().getActivities()) {
if (activity.getId() == null) {
activityRepository.save(mapToJpa(activity));
activityRepository.save(accountMapper.mapToJpaEntity(activity));
}
}
}
private ActivityJpaEntity mapToJpa(Activity activity) {
return new ActivityJpaEntity(
activity.getId() == null ? null : activity.getId().getValue(),
activity.getTimestamp(),
activity.getOwnerAccountId().getValue(),
activity.getSourceAccountId().getValue(),
activity.getTargetAccountId().getValue(),
activity.getMoney().getAmount().longValue());
}
}

View File

@@ -0,0 +1,4 @@
package io.reflectoring.cashpal.adapter.web;
class AccountResource {
}

View File

@@ -4,12 +4,9 @@ import io.reflectoring.cashpal.application.port.in.SendMoneyUseCase;
import io.reflectoring.cashpal.application.port.in.SendMoneyUseCase.SendMoneyCommand;
import io.reflectoring.cashpal.domain.Account.AccountId;
import io.reflectoring.cashpal.domain.Money;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
@@ -18,24 +15,18 @@ public class SendMoneyController {
private final SendMoneyUseCase sendMoneyUseCase;
@PostMapping(path = "/sendMoney")
void sendMoney(@RequestBody SendMoneyForm form) {
@PostMapping(path = "/accounts/sendMoney/{sourceAccountId}/{targetAccountId}/{amount}")
void sendMoney(
@PathVariable("sourceAccountId") Long sourceAccountId,
@PathVariable("targetAccountId") Long targetAccountId,
@PathVariable("amount") Long amount) {
SendMoneyCommand command = new SendMoneyCommand(
new AccountId(form.sourceAccountId),
new AccountId(form.targetAccountId),
Money.of(form.amount));
new AccountId(sourceAccountId),
new AccountId(targetAccountId),
Money.of(amount));
sendMoneyUseCase.sendMoney(command);
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class SendMoneyForm {
private Long sourceAccountId;
private Long targetAccountId;
private Long amount;
}
}

View File

@@ -1,7 +1,5 @@
package io.reflectoring.cashpal.adapter.web;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.reflectoring.cashpal.adapter.web.SendMoneyController.SendMoneyForm;
import io.reflectoring.cashpal.application.port.in.SendMoneyUseCase;
import io.reflectoring.cashpal.application.port.in.SendMoneyUseCase.SendMoneyCommand;
import org.junit.jupiter.api.Test;
@@ -22,20 +20,11 @@ class SendMoneyControllerTest {
@MockBean
private SendMoneyUseCase sendMoneyUseCase;
private ObjectMapper jsonMapper = new ObjectMapper();
@Test
void testSendMoney() throws Exception {
SendMoneyForm form = new SendMoneyForm(
41L,
42L,
500L
);
mockMvc.perform(post("/sendMoney")
.header("Content-Type", "application/json")
.content(jsonMapper.writeValueAsString(form)))
mockMvc.perform(post("/accounts/sendMoney/{sourceAccountId}/{targetAccountId}/{amount}", 41L, 42L, 500)
.header("Content-Type", "application/json"))
.andExpect(status().isOk());
then(sendMoneyUseCase).should().sendMoney(any(SendMoneyCommand.class));

View File

@@ -17,15 +17,18 @@ public interface SendMoneyUseCase {
class SendMoneyCommand extends SelfValidating<SendMoneyCommand> {
@NotNull
private Account.AccountId sourceAccountId;
private final Account.AccountId sourceAccountId;
@NotNull
private Account.AccountId targetAccountId;
private final Account.AccountId targetAccountId;
@NotNull
private Money money;
private final Money money;
public SendMoneyCommand(Account.AccountId sourceAccountId, Account.AccountId targetAccountId, Money money) {
public SendMoneyCommand(
Account.AccountId sourceAccountId,
Account.AccountId targetAccountId,
Money money) {
this.sourceAccountId = sourceAccountId;
this.targetAccountId = targetAccountId;
this.money = money;

View File

@@ -53,7 +53,9 @@ public class Account {
* Calculates the total balance of the account by adding the activity values to the baseline balance.
*/
public Money calculateBalance() {
return Money.add(this.activityWindow.calculateBalance(this.id), this.baselineBalance);
return Money.add(
this.baselineBalance,
this.activityWindow.calculateBalance(this.id));
}
/**
@@ -63,22 +65,39 @@ public class Account {
*/
public boolean withdraw(Money money, AccountId targetAccountId) {
if(Money.add(this.calculateBalance(), money.negate()).isNegative()){
if (!mayWithdraw(money)) {
return false;
}
Activity withdrawal = new Activity(null, this.id, this.id, targetAccountId, LocalDateTime.now(), money);
Activity withdrawal = new Activity(
this.id,
this.id,
targetAccountId,
LocalDateTime.now(),
money);
this.activityWindow.addActivity(withdrawal);
return true;
}
private boolean mayWithdraw(Money money) {
return Money.add(
this.calculateBalance(),
money.negate())
.isPositiveOrZero();
}
/**
* Tries to deposit a certain amount of money to this account.
* If sucessful, creates a new activity with a positive value.
* @return true if the deposit was successful, false if not.
*/
public boolean deposit(Money money, AccountId sourceAccountId) {
Activity deposit = new Activity(null, this.id, sourceAccountId, this.id, LocalDateTime.now(), money);
Activity deposit = new Activity(
this.id,
sourceAccountId,
this.id,
LocalDateTime.now(),
money);
this.activityWindow.addActivity(deposit);
return true;
}

View File

@@ -4,16 +4,18 @@ import java.time.LocalDateTime;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.Value;
/**
* A money transfer activity between {@link Account}s.
*/
@Value
@RequiredArgsConstructor
public class Activity {
@Getter
private final ActivityId id;
private ActivityId id;
/**
* The account that owns this activity.
@@ -50,6 +52,20 @@ public class Activity {
@NonNull
private final Money money;
public Activity(
@NonNull Account.AccountId ownerAccountId,
@NonNull Account.AccountId sourceAccountId,
@NonNull Account.AccountId targetAccountId,
@NonNull LocalDateTime timestamp,
@NonNull Money money) {
this.id = null;
this.ownerAccountId = ownerAccountId;
this.sourceAccountId = sourceAccountId;
this.targetAccountId = targetAccountId;
this.timestamp = timestamp;
this.money = money;
}
@Value
public static class ActivityId {
private final Long value;

View File

@@ -37,6 +37,14 @@ public class Money {
return new Money(a.amount.add(b.amount));
}
public Money minus(Money money){
return new Money(this.amount.subtract(money.amount));
}
public Money plus(Money money){
return new Money(this.amount.add(money.amount));
}
public static Money subtract(Money a, Money b) {
return new Money(a.amount.subtract(b.amount));
}

View File

@@ -60,11 +60,8 @@ class SendMoneyServiceTest {
@Test
void transactionSucceeds() {
AccountId sourceAccountId = new AccountId(41L);
Account sourceAccount = givenAnAccountWithId(sourceAccountId);
AccountId targetAccountId = new AccountId(42L);
Account targetAccount = givenAnAccountWithId(targetAccountId);
Account sourceAccount = givenSourceAccount();
Account targetAccount = givenTargetAccount();
givenWithdrawalWillSucceed(sourceAccount);
givenDepositWillSucceed(targetAccount);
@@ -72,14 +69,17 @@ class SendMoneyServiceTest {
Money money = Money.of(500L);
SendMoneyCommand command = new SendMoneyCommand(
sourceAccountId,
targetAccountId,
sourceAccount.getId(),
targetAccount.getId(),
money);
boolean success = sendMoneyService.sendMoney(command);
assertThat(success).isTrue();
AccountId sourceAccountId = sourceAccount.getId();
AccountId targetAccountId = targetAccount.getId();
then(accountLock).should().lockAccount(eq(sourceAccountId));
then(sourceAccount).should().withdraw(eq(money), eq(targetAccountId));
then(accountLock).should().releaseAccount(eq(sourceAccountId));
@@ -121,6 +121,14 @@ class SendMoneyServiceTest {
.willReturn(true);
}
private Account givenTargetAccount(){
return givenAnAccountWithId(new AccountId(42L));
}
private Account givenSourceAccount(){
return givenAnAccountWithId(new AccountId(41L));
}
private Account givenAnAccountWithId(AccountId id) {
Account account = Mockito.mock(Account.class);
given(account.getId())