【问题标题】:spring-boot: test @service classspring-boot:测试@service类
【发布时间】:2016-09-11 11:36:03
【问题描述】:

我对 Spring Boot 和测试有点陌生。我想测试这个@Service 类:

@Service
public class TransactionService {

    private MessagingService messagingService;
    private CustomerRepository customerRepository;

    private static final Logger log = LoggerFactory.getLogger(TransactionService.class);

    @Autowired
    public TransactionService(MessagingService messagingService, CustomerRepository customerRepository){
        Assert.notNull(messagingService, "MessagingService cannot be null");
        this.messagingService = messagingService;
        Assert.notNull(customerRepository, "CustomerRepository cannot be null");
        this.customerRepository = customerRepository;
    }

    public void makeTransactionFromSenderToReceiver(Customer sender, Customer receiver, int amount) {

        if (sender.getBalance() >= amount) {
            sender.setBalance(sender.getBalance() - amount);
            receiver.setBalance(receiver.getBalance() + amount);

            customerRepository.save(sender);
            customerRepository.save(receiver);
        }

        else {
            throw new CustomerBalanceExceededException();
        }
    }
}

在我的武器库中,我有 spring-boot-starter-test maven 依赖项进行测试。我设法像这样测试了我的 Customer 类:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
public class CustomerTests
{
  @Autowired
  private CustomerRepository repository;

  @Test
  public void testCreate()
  {
    final Customer customer = new Customer();
    customer.setName("CoolGuy");

    Assert.notNull(repository.save(customer));
  }
}

我目前不知道如何测试上面定义的@Service 类的方法的功能。任何提示都非常感谢。

编辑:我试过写一个测试,但我认为这不是测试这个逻辑的正确方法。任何帮助将不胜感激:

TransactionServiceTests.class

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
public class TransactionServiceTests {

    @Autowired
    private CustomerRepository repository;

    @Autowired
    private TransactionService transactionService;

    @Test
    public void testTransactionBetweenCustomersAndBalanceOfReceiver() {

        int AMOUNT = 50;

        Customer customerOksana = repository.findByName("Oksana");
        Customer customerDeniss = repository.findByName("Deniss");

        transactionService.makeTransactionFromSenderToReceiver(customerDeniss, customerOksana, AMOUNT);
        assertThat(customerOksana.getBalance()).isEqualTo(customerOksana.getBalance());
    }

    @Test
    public void testTransactionBetweenCustomersAndBalanceOfSender() {

        int AMOUNT = 40;

        Customer customerOksana = repository.findByName("Oksana");
        Customer customerDeniss = repository.findByName("Deniss");

        transactionService.makeTransactionFromSenderToReceiver(customerDeniss, customerOksana, AMOUNT);
        assertThat(customerDeniss.getBalance()).isEqualTo(customerDeniss.getBalance());
    }
}

【问题讨论】:

  • 您是要进行单元测试、集成还是两者兼而有之?
  • 两项测试都需要。
  • 这不能回答您的问题,但您的 TransactionService 中的 Assert 类型似乎不正确。我认为您正在寻找 assert docs.oracle.com/javase/7/docs/technotes/guides/language/… 而不是 JUnit Assert
  • docs.spring.io/spring/docs/current/javadoc-api/org/…我认为在这种情况下是正确的。
  • 我要更改的另一件事是将private static final Logger log = LoggerFactory.getLogger(Application.class); 更改为private static final Logger log = LoggerFactory.getLogger(TransactionService.class); 一般做法是将调用类用作记录器,以便您可以更好地理解和过滤来自代码特定部分的日志记录。您可以为记录器使用不同的类,但我认为这不是一般做法。

标签: java testing spring-boot


【解决方案1】:

单元测试,请参阅 Mockito 或其他一些模拟框架。您甚至不需要对测试类本身进行任何注释。您想测试方法调用并验证与其他类的交互以及结果是否符合您的预期。

这是使用 Mockito 进行单元测试的示例。显然,您希望充实这一点并添加更多测试。这将为您提供代码覆盖率,并验证前置条件和后置条件。这不会测试存储库代码是否正确映射或事务边界是否按预期工作,这必须使用集成测试来完成。

public class TransactionServiceTest {

    @Rule
    public MockitoRule mockitoRule = MockitoJUnit.rule();

    @Mock
    private MessagingService mockMessagingService;
    @Mock
    private CustomerRepository mockCustomerRepository;

    @Test
    public void testMakeTransactionFromSenderToReceiver() {
        // setup the state of the sender and receiver
        Customer sender = new Customer();
        sender.setBalance(5.0);
        Customer receiver = new Customer();
        receiver.setBalance(10.0);
        TransactionService transactionService = new TransactionService(mockMessagingService, mockCustomerRepository);

        transactionService.makeTransactionFromSenderToReceiver(sender, receiver);

        // assert the expected state of the Customer objects
        assertEquals(1.0, sender.getBalance());
        assertEquals(1.0, receiver.getBalance());

        // verify that the repositories were called appropriately once
        // this can be made to be more specific and check the argument that was passed - see Mockito documentation
        verify(mockCustomerRepository, times(2)).save(any());
    }

}

您的断言逻辑不正确

@Test
public void testTransactionBetweenCustomersAndBalanceOfReceiver() {

    int AMOUNT = 50;

    Customer customerOksana = repository.findByName("Oksana");
    Customer customerDeniss = repository.findByName("Deniss");

    transactionService.makeTransactionFromSenderToReceiver(customerDeniss, customerOksana, AMOUNT);
    assertThat(customerOksana.getBalance()).isEqualTo(customerOksana.getBalance());
}

您是在断言同一个实例具有相同的余额。这将永远是真的。您想通过将新客户保存到存储库或在执行您的方法 makeTransactionFromSenderToReceiver 之前获取原始余额来检查调整是否符合您的预期。

@Test
public void testTransactionBetweenCustomersAndBalanceOfReceiver() {

    int AMOUNT = 50;

    // prepare your test data unless you always expect those values to exist.
    Customer customerReceiver = new Customer();
    customerReciever.setName("Oksana");
    customerReceiver.setBalance(12);
    customerReceiver = repository.save(customerReceiver);

    Customer customerSender = new Customer();
    customerSender.setName("Deniss");
    customerSender.setBalance(5);
    customerSender = repository.save(customerSender);

    // assign before executing method
    int expectedReceiverAmount = customerReceiver.getBalance() + AMOUNT;
    int expectedSenderAmount = customerSender.getBalance() - AMOUNT;
    transactionService.makeTransactionFromSenderToReceiver(customerSender, customerReceiver, AMOUNT);

    assertEquals(expectedSenderAmount, customerSender.getBalance());
    assertEquals(expectedReceiverAmount, customerReceiver.getBalance());
}

【讨论】:

  • 谢谢!一个非常详细的答案!
猜你喜欢
  • 2018-06-10
  • 2019-06-01
  • 2022-11-11
  • 2018-02-25
  • 2019-01-29
  • 2019-01-21
  • 1970-01-01
  • 2019-03-13
  • 2016-10-29
相关资源
最近更新 更多