Upgrade to Pro — share decks privately, control downloads, hide ads and more …

単体テストの始め方/作り方

Avatar for toms toms
June 06, 2025

 単体テストの始め方/作り方

JJUG CCC 2025 Spring の発表資料
https://ccc2025spring.java-users.jp/

Zennの記事: https://zenn.dev/toms74209200/articles/first-step-unit-testing

# 参考文献

- 単体テストの考え方/使い方 プロジェクトの持続可能な成長を実現するための戦略, Vladimir Khorikov, 須田 智之, マイナビ出版, 2022 http://book.mynavi.jp/ec/products/detail/id=134252
- テスト駆動開発, Kent Beck, 和田 卓人, オーム社, 2017 https://www.ohmsha.co.jp/book/9784274217883/
- Googleのソフトウェアエンジニアリング―持続可能なプログラミングを支える技術、文化、プロセス, Titus Winters, Tom Manshreck, Hyrum Wright, 竹辺 靖昭, 久富木 隆一, オライリー・ジャパン, 2021 https://www.oreilly.co.jp/books/9784873119656/

Avatar for toms

toms

June 06, 2025
Tweet

More Decks by toms

Other Decks in Programming

Transcript

  1. まずは現行のコードを見てみよう public Order processOrder(OrderRequest request) throws InvalidOrderException, Insuff i cientStockException

    { Product product = productRepository.f i ndByCode(request.productCode()).orElse(null); if (product = = null) { throw new InvalidOrderException("ଘࡏ͠ͳ͍঎඼ίʔυͰ͢ɻ"); } if (request.quantity() > product.stock()) { throw new Insuff i cientStockException("ࡏݿ͕ෆ଍͍ͯ͠·͢ɻ"); } return orderRepository.save(new Order(request.productCode(), request.quantity())); }
  2. public Order processOrder(OrderRequest request) throws InvalidOrderException, Insuff i cientStockException {

    Product product = productRepository.f i ndByCode(request.productCode()).orElse(null); if (product = = null) { throw new InvalidOrderException("ଘࡏ͠ͳ͍঎඼ίʔυͰ͢ɻ"); } if (request.quantity() > product.stock()) { throw new Insuff i cientStockException("ࡏݿ͕ෆ଍͍ͯ͠·͢ɻ"); } return orderRepository.save(new Order(request.productCode(), request.quantity())); } 商品コードから商品を検索 在庫の確認 注文を登録 まずは現行のコードを見てみよう
  3. public Order processOrder(OrderRequest request) throws InvalidOrderException, Insuf fi cientStockException {

    Product product = productRepository. fi ndByCode(request.productCode()).orElse(null); if (product == null) { throw new InvalidOrderException("ଘࡏ͠ͳ͍঎඼ίʔυͰ͢ɻ"); } + if (product.isReservation()) { + return orderRepository.save(new Order(request.productCode(), request.quantity(), OrderType.RESERVATION)); + } if (request.quantity() > product.stock()) { throw new Insuf fi cientStockException("ࡏݿ͕ෆ଍͍ͯ͠·͢ɻ"); } + return orderRepository.save(new Order(request.productCode(), request.quantity(), OrderType.NORMAL)); } 予約注文機能を追加してみる できた🎉🎉🎉🎉🎉🎉🎉
  4. public Order processOrder(OrderRequest request) throws InvalidOrderException, Insuf fi cientStockException {

    Product product = productRepository. fi ndByCode(request.productCode()).orElse(null); if (product == null) { throw new InvalidOrderException("ଘࡏ͠ͳ͍঎඼ίʔυͰ͢ɻ"); } + if (product.isReservation()) { + return orderRepository.save(new Order(request.productCode(), request.quantity(), OrderType.RESERVATION)); + } if (request.quantity() > product.stock()) { throw new Insuf fi cientStockException("ࡏݿ͕ෆ଍͍ͯ͠·͢ɻ"); } + return orderRepository.save(new Order(request.productCode(), request.quantity(), OrderType.NORMAL)); } テストも書いて🙋 🤔 どうやって?
  5. テスト駆動開発 AAAパターン / / Arrange: ஫จ঎඼͕༧໿঎඼ Product product = new

    Product(); product.setIsReservation(true); / / Act: ஫จΛ͢Δ orderService.processOrder(new OrderRequest(product.getProductCode(), 1); / / Assert: ༧໿஫จͱͯ͠ొ࿥͞ΕΔ͔ List<Order> orders = orderRepository.f i ndByProductCode(product.getProductCode()); assertThat(orders.get(0).getStatus()).isEqualTo(OrderType.RESERVATION); テストコードと日本語のコメントが1:1で対応する
  6. / / Arrange: ஫จ঎඼͕༧໿঎඼ Product product = new Product(); product.setIsReservation(true);

    / / Act: ஫จΛ͢Δ orderService.processOrder(new OrderRequest(product.getProductCode(), 1); / / Assert: ༧໿஫จͱͯ͠ొ࿥͞ΕΔ͔ List<Order> orders = orderRepository.f i ndByProductCode(product.getProductCode()); assertThat(orders.get(0).getStatus()).isEqualTo(OrderType.RESERVATION); テスト駆動開発 AAAパターン 🤔 このままだと動かない Productはどうやってわたす?
  7. リファクタリングして・・・できた🎉🎉🎉🎉🎉🎉🎉 / / Arrange: ஫จ঎඼͕༧໿঎඼ OrderRequest orderRequest = setupAndOrderReservationProductWithDefaultQuantity(); OrderService

    orderService = OrderServiceFactoryForTest.createOrderService(); / / Act: ஫จΛ͢Δ Order order = orderService.order(orderRequest); / / Assert: ༧໿஫จͱͯ͠ొ࿥͞ΕΔ verifyOrderIsReservationProduct(order);
  8. / / Arrange: ஫จ঎඼͕༧໿঎඼ OrderRequest orderRequest = setupAndOrderReservationProductWithDefaultQuantity(); OrderService orderService

    = OrderServiceFactoryForTest.createOrderService(); / / Act: ஫จΛ͢Δ Order order = orderService.order(orderRequest); / / Assert: ༧໿஫จͱͯ͠ొ࿥͞ΕΔ verifyOrderIsReservationProduct(order); わかりにくいのでやり直し 🙅
  9. テストはDRYよりDAMP(Descriptive And Meaningful Phrases) テストはより説明的に String productCode = "product123"; Product

    product = new Product(); product.setPreOrder(true); product.setCode(productCode); when(inventoryRepository.f i ndByCode(productCode)) .thenReturn(product);