测试接口还是class?
Testing interface or class?
我是 java 的新手,我对使用 JUnit 和 Mockito 测试代码感到困惑。
我在 github 上创建了一个项目,任务是为以下项目编写 Junit 测试
AccountService
这是一个接口。我不知道我必须测试什么?接口或实现接口的 class ?
这里是AccountService
:
public interface AccountService {
public Operation deposit(String accountNumber, int amount);
public Operation withdraw(String accountNumber, int amount);
public OperationsDto history(String accountNumber);
}
这是AccountService
实现
@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);
}
}
}
您应该测试实施,因此 class。
接口只能用于注入。因此,查看您发布的代码,您应该在 AccountServiceImplTest
class (或类似的东西)中测试 AccountServiceImpl
class。
在此单元测试中,您应该模拟 AccountRepository
、OperationRepository
和 OperationConverter
。在测试单元中,您应该只测试对测试感兴趣的 class,而不是它的依赖项。因此,您使用 @Autowired
注入接口。通过这种方式,使用模拟框架,您可以模拟 class 依赖项,隔离您需要测试的单元。
看看您发布的 class:您正在使用注释注入三个 bean。我很确定那些类型都是接口。当您部署应用程序时,Spring CDI 将负责在启动容器(或右 运行 Spring Boot)后立即注入实际实现。当你是运行这个class的时候,你想要隔离它。测试应尽可能原子化。将 Mockito 与正确的 JUnit 运行器一起使用,您将为注入的 bean 提供伪造的实现。使用 Mockito API 你可以知道这个伪造的实现应该如何回答某个请求。因此,您采用 AccountServiceImpl
的实现,模拟其所有依赖项,然后仅测试 class 中包含的逻辑。你不测试接口,因为接口只代表调用服务的契约,而不是它的实现。
@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*/
}
}
这就是您的测试 class 的显示方式。
我是 java 的新手,我对使用 JUnit 和 Mockito 测试代码感到困惑。
我在 github 上创建了一个项目,任务是为以下项目编写 Junit 测试
AccountService
这是一个接口。我不知道我必须测试什么?接口或实现接口的 class ?
这里是AccountService
:
public interface AccountService {
public Operation deposit(String accountNumber, int amount);
public Operation withdraw(String accountNumber, int amount);
public OperationsDto history(String accountNumber);
}
这是AccountService
实现
@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);
}
}
}
您应该测试实施,因此 class。
接口只能用于注入。因此,查看您发布的代码,您应该在 AccountServiceImplTest
class (或类似的东西)中测试 AccountServiceImpl
class。
在此单元测试中,您应该模拟 AccountRepository
、OperationRepository
和 OperationConverter
。在测试单元中,您应该只测试对测试感兴趣的 class,而不是它的依赖项。因此,您使用 @Autowired
注入接口。通过这种方式,使用模拟框架,您可以模拟 class 依赖项,隔离您需要测试的单元。
看看您发布的 class:您正在使用注释注入三个 bean。我很确定那些类型都是接口。当您部署应用程序时,Spring CDI 将负责在启动容器(或右 运行 Spring Boot)后立即注入实际实现。当你是运行这个class的时候,你想要隔离它。测试应尽可能原子化。将 Mockito 与正确的 JUnit 运行器一起使用,您将为注入的 bean 提供伪造的实现。使用 Mockito API 你可以知道这个伪造的实现应该如何回答某个请求。因此,您采用 AccountServiceImpl
的实现,模拟其所有依赖项,然后仅测试 class 中包含的逻辑。你不测试接口,因为接口只代表调用服务的契约,而不是它的实现。
@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*/
}
}
这就是您的测试 class 的显示方式。