1

I'm new to java and I'm confused about testing code with JUnit and Mockito.

I have forked a project on github where the task is to write Junit testing for AccountService which is an interface. What I don't know is what do I have to test ? Interface or class that implement interface ?

Here is AccountService:

public interface AccountService {
    public Operation deposit(String accountNumber, int amount);
    public Operation withdraw(String accountNumber, int amount);
    public OperationsDto history(String accountNumber);
}

Here is AccountService implementation

@Service
public class AccountServiceImpl implements  AccountService {

    @Autowired
    private AccountRepository accountRepository;
    @Autowired
    private OperationRepository operationRepository;

    @Autowired
    OperationConverter operationConverter;


    public Operation deposit(String accountNumber, int amount) {
        checkAmount (amount);

        AccountEntity account = getAccount (accountNumber);

        int balance =  account.getBalance();
        balance = balance + amount;

        OperationEntity operation = new OperationEntity();
        operation.setAccount(accountNumber);
        operation.setAmount(amount);
        operation.setType(OperationType.DEPOSIT.toString());
        operation.setDate(DateUtil.getCurrentDate());
        operation.setBalance(balance);

        operationRepository.save(operation);

        //update account balance
        account.setBalance(balance);
        accountRepository.save(account);

        return  operationConverter.convert(operation);
    }

    public Operation withdraw(String accountNumber, int amount) {
        checkAmount (amount);

        AccountEntity account = getAccount (accountNumber);

        int balance = account.getBalance();
        balance = balance - amount;
        if(balance < 0){
            throw new OperationException(Constants.ERROR_INVALID_OPERATION);
        }

        OperationEntity operation = new OperationEntity();
        operation.setBalance(balance);
        operation.setAccount(accountNumber);
        operation.setAmount(amount);
        operation.setType(OperationType.WITHDRAW.toString());
        operation.setDate(DateUtil.getCurrentDate());

        operationRepository.save(operation);

        //update account balance
        account.setBalance(balance);
        accountRepository.save(account);

        return  operationConverter.convert(operation);
    }

    public OperationsDto history(String accountNumber) {
        List<OperationEntity>  operations = 
        operationRepository.findByAccount(accountNumber);
        return operationConverter.convertList(operations);
    }

    private AccountEntity getAccount(String accountNumber){

        AccountEntity account = 
        accountRepository.findByNumber(accountNumber);

        if(account == null) {
            throw new AccountException(Constants.ERROR_INVALID_ACCOUNT);
        }

        return account;
    }

    private void checkAmount (int amount) {
        if(amount < 0){
            throw new OperationException(Constants.ERROR_INVALID_OPERATION);
        }
    }
}
2
  • do you have any preferences to which junit api to use.. mockito.. powermock.. easymock.. powermockito Commented May 22, 2018 at 12:43
  • @amRika I'm using mockito :) Commented May 22, 2018 at 12:52

1 Answer 1

6

You should test the implementation, hence, the class.

The interface should be used only for injections. So, looking to the code you have posted, you should test the AccountServiceImpl class in a AccountServiceImplTest class (or something similar).

In this Unit test you should mock AccountRepository, OperationRepository and OperationConverter. In a test unit you should test only the class which is interested in test, not its dependencies. So, You inject the interfaces using @Autowired. In this way using a mock framework you can mock your class dependencies, isolating the unit you need the test.

Look at the class you posted: you are injecting three beans using an annotation. I'm pretty sure that those types are all interfaces. When you deploy the application, the Spring CDI will take care of injecting the actual implementations right after starting the container (or right running Spring Boot). When you are running this class, you want to isolate it. The test should be as atomic as possible. Using Mockito along with the correct JUnit runner, you will provide a fake implementation for the injected beans. Using Mockito API you can tell how this fake implementation should answer to a certain request. So you take the implementation of AccountServiceImpl, mock all its dependencies and than you test only the logic contained in that class. You do not test an interface, because an interface represents only the contract for calling a service, not its implementation.

@RunWith(MockitoJUnitRunner.class)
public class AccountServiceTest {

@Mock
private AccountRepository accountRepository;

@Mock
private OperationRepository operationRepository;

@Mock
OperationConverter operationConverter;

@InjectMocks
private AccountServiceImpl accountService;

@Before
public void setUp() {
    /* here goes before-class init logic */
}

@Test
public void testMethod1() {
    /* here you test a method*/
}

@Test
public void testMethod2() {
    /* here you test another method*/
}
}

This is how your test class should appear.

Sign up to request clarification or add additional context in comments.

1 Comment

Can you please give me an example ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.