0

I have method, that sets money to account.

public Optional<Account> addMoneyToBalance(Long id, Float money) {
        Optional<Account> accountFromDb = accountRepository.findById(id);
        float result;
        if (accountFromDb.isPresent()) {
            Account account = accountFromDb.get();
            result = account.getTotalBalance();
            result += money;
            account.setTotalBalance(result);
            accountRepository.save(account);
        }else throw new AccountNotFoundException("Account not found");

        return accountFromDb;
    }

If I try save accountRepository.save(account), will it change data in database(accountFromDB)?

Is it correct test? :

@RunWith(SpringRunner.class)
@SpringBootTest
public class FrugalBudgetingApplicationTests {

    @Autowired
    private AccountService accountService;
    @Autowired
    private AccountRepository accountRepository;


    @Test
    public void contextLoads() {
        List<Bank> banks = new ArrayList<>();
        banks.add(new Bank("OTP", 1239.2f));
        banks.add(new Bank("UKRsib", 549.2f));
        Account account = new Account(1912.2f, 200.45f, banks);
        accountRepository.save(account);
        Optional<Account> account1 = accountService.addMoneyToBalance(1L, 92f);
        Assert.assertNull(account1);
    }

}

Result of test:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.korzhov.frugalbudgeting.entities.Account.banks, could not initialize proxy - no Session
    at java.base/java.lang.String.valueOf(String.java:2951)
    at java.base/java.lang.StringBuilder.append(StringBuilder.java:168)
    at com.korzhov.frugalbudgeting.entities.Account.toString(Account.java:15)
    at java.base/java.util.Formatter$FormatSpecifier.printString(Formatter.java:3031)
    at java.base/java.util.Formatter$FormatSpecifier.print(Formatter.java:2908)
com.korzhov.frugalbudgeting.FrugalBudgetingApplicationTests.contextLoads(FrugalBudgetingApplicationTests.java:36)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)

I dont know exactly, what I have to test in this method. I tried to test for NullPointerException account from Db.

andrew17
  • 851
  • 2
  • 10
  • 25

1 Answers1

0

Judging by the snippet of code you provided what you are currently doing is integration test, which connects to the real database (without seeing your pom/gradle.build file i cannot tell which one but I will assume H2).

If i save accountRepository.save(account), will it change data in database(accountFromDB)?

Yes, if you save account it will be actually inserted into test database.

is it true test?

Yes, it is. This type of test is called integration test. Another type of test that I would recommend you to look into is unit test. A good explanation of unit tests can be found here.

result of test:

Your test didn't execute properly, you are receiving an exception. Your stack trace is saying that you are somewhere trying to fetch accounts.banks but you are missing a session. To fix it you should put @Transactional on your test method.

@Test
@Transactional
public void contextLoads() {
....

Honestly, i dont even know, what i have to test in this method. So i tried to test for NullPointer account from Db.

When testing you should always ask yourself what am I trying to test? In this test you are trying to test method which adds money to the account. So first thing that I would test is that account is getting returned after method execution (account is not null). After that I would test that account balance is increased exactly by amount you put in addMoneyToBalance method. There is also one other thing that should be tested in another test. And that is the case when you are adding money to account that doesn't exists. In that test you should assert that AccountNotFoundException is thrown.

Lorelj
  • 61
  • 3
  • thanks! Could you tell, if my opinion is true: when i get() from accountFromDB(Optional) = just account object(without Optional), and changing data there, so it means that i am changing data in Optional and it will return changed data? Or I return difference objects and have to do after manages smth like that: a = account.getData() and accountFromDb.setData(a)? – andrew17 Nov 10 '19 at 22:39
  • And i missed, I used assertNull instead of assertNotNull. Didnt know that its usefull to check if its fine that method returns null – andrew17 Nov 10 '19 at 22:47
  • I don't know if I understood your question correctly but optional is just a container for object, in your case Account that allows better handling of null values. You can read more about optional here https://www.baeldung.com/java-optional. So when you perform get() you are getting instance of Account object which you can modify, and later save changes to database or do whatever you like. – Lorelj Nov 11 '19 at 09:37