見出し画像

【Java&SpringBoot3】 早起きのWebアプリー機能追加(2)「フォロー」機能(設計・実装・テスト)


1. はじめ


こんにちは!

今日は昨日に続きフォロー機能の設計・実装・テストまで、Waterfall工程方式の流れで開発してみます!


2. 「フォロー」機能の基本設計(07.26-07.27)


基本設計では、提供したいサービスを実験するためにアプリケーションがどういった動作をするのかを設計します。

  • アプリケーションの持つ機能の一覧

  • アプリケーションの構成図

  • 画面レイアウト

などを検討します。

ざっくりとした言い方をすれば、アプリケーションの表面的な部分の設計となります。

そのため基本設計は外部設計ともよばれます。


(*参考:『Web技術の基本』、p.180)

2.1 目的

関心のあるユーザーを登録し、お互いに朝起きのモチベーションを与える。

2.2 機能構成

1.登録者の記録の中でフォローボタンを押すと相手をフォローする。
2.アンフォローボタンを押すと相手をアンフォローする。
3.自分のフォローするユーザーの数とリストを表示する。
4.自分をフォローするユーザーの数とリストを表示する。


2.3 画面構成

KakaoOvenというUI構成ツールで作成しますた。

1. 登録者をフォローまたはアンフォローする
 2. 画面の右側にログインユーザー
・フォロー中・フォローワの数を表示する


 3. フォローイ中の数を押下時、一覧を表示する
* アンフォロボタンはフォロー中で表示する


4. 以前・以後のボタンを押下時、一覧が変わる

2.4 データベースモデリング

フォロワー関係を示すために、ユーザー(User)エンティティとフォロワー(Follower)エンティティの間の一対多関係を定義する。 フォロワーエンティティは、各ユーザーがフォローする他のユーザーの情報を保存する。

「user」テーブルと「follow」テーブルの間の関係
  • id:フォロー関係の固有の識別子で、デフォルトキーに設定されています。

  • following_user_id:フォローするユーザーのidを保存します。

  • followed_user_id:フォローされるユーザーのidを保存します。

  • created_at:フォロー関係が生成された時間を保存します。この例はフォローリストをフォローした順番で整列するために作りました。


テーブル間の関係説明

  • "user" テーブルのid列と"follow" テーブルのfollowing_user_id列の間に1:N関係があります。 つまり、1 つのユーザーは複数のフォローすることができます

  • "user" テーブルのid列と "follow" テーブルのfollowed_user_id列との間に1:N関係があります。 つまり、1 つのユーザーは複数のフォローされることができます


3.「フォロー」機能の詳細設計と実装(07.28-08.03)


3.1 UML - シーケンスダイアグラム

シーケンスダイアグラムは、システムの動的な動作を表現するために使用されます。 オブジェクト間の相互作用を時間順に示します。

オブジェクト(Object)
四角形で表現され、システム内のオブジェクトを表します。 オブジェクトはダイアグラム上に垂直に表示される。

メッセージ(Message)
実線で表示し、オブジェクト間でやり取りするメッセージを表現します。 送信者オブジェクトから受信者オブジェクトに移動する方向で表示されます。 メッセージには、呼び出されるメソッドの名前と渡されるパラメータなどが含まれます。

ライフライン
オブジェクトが存在する期間を示します。 ライフラインはオブジェクトの垂直線で表現され、オブジェクトがメッセージを受信している間に存在する時間を示します。

返却メッセージ(Return Message)
点線で表示し、メソッド呼び出しに対する応答として返されるメッセージを示します。

フォロー登録
アンフォロ(フォロー削除)
フォローリストでアンフォロ(フォロー削除)

3.2 Domain - Follow.java

@Table(name = "follow")
@EntityListeners(AuditingEntityListener.class)
@NoArgsConstructor(access = AccessLevel.PUBLIC)
@Data
@Entity
public class Follow {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", updatable = false)
    private Long id;


    @Column(name = "following_user_id", nullable = false)
    private String following;


    @Column(name = "followed_user_id", nullable = false)
    private String followed;

    @CreatedDate
    @Column(name = "created_at")
    private LocalDateTime createdAt;

    @Builder
    public Follow(String following, String followed) {
        this.following = following;
        this.followed = followed;

    }

}

上記のコードは、Followというエンティティクラスを定義したものです。 このクラスはデータベースのフォロー テーブルとマッピングされ、フォロー関係を示す情報を保存します。 クラスにはid、following、followed、createdAtというフィールドがあります。
idフィールドは、固有な識別子です。

followingフィールドは、フォローするユーザーのメールを保存します。

followedフィールドは、そのユーザーをフォローする対象ユーザーの電子メールを保存します。

createdAtフィールドは、そのフォロー関係が生成された時間を保存します。

また、@Builderアノテーションを使用して生成者を生成し、

@EntityListeners(AuditingEntityListener.class)アノテーションを使用して自動的に生成時間を処理します。このアノテーションは、JPAにおいてエンティティの生成及び修正時点で自動的に監視(監視機能の活性化)するよう指定するアノテーションです。
このクラスは、Lombokの@Dataアノテーションを通じて自動的にgetter、setterなどのメソッドを生成するように設定されています。

上で注目すべき部分が一つあります。 外来鍵を別に設定していないことです。データ関係の複雑さから外来鍵を使わないこともあります。 RESTRICTやCASCADEオプションを入れたり入れなかったり、どちらにしても開発者の立場で気を使わなければならない部分が増えるためです。 データの量が多くなり、関係が複雑になるほど、さらにひどくなります。

たとえば、参照されるリレーションは、参照するリレーションよりも先に作成されている必要があります。 そのため、生成、修正するたびに順番を気にしなければならない煩わしさが発生します。

CASCADEに設定しておいた場合、一つのリレーションのデータを誤って変えた場合、参照するリレーションのデータがすべて変更されるため、特にデータを保存することが重要なシステムでは外来鍵を使わない方がより安定的であると考えられます。


3.3 Repository - FollowRepository.java

public interface FollowRepository extends JpaRepository<Follow, Long> {

    // フォローとフォロワーでレコードを探す
    Follow findByFollowingAndFollowed(String following, String followed);

    // 現在ログインしているユーザーのフォローしているユーザー数の照会
    @Query(value = "SELECT COUNT(*) FROM follow WHERE following_user_id = ?1", nativeQuery = true)
    Long countByFollowing(String followingUser);

    // 現在ログインしているユーザーのをフォローしているユーザー数の照会
    @Query(value = "SELECT COUNT(*) FROM follow WHERE followed_user_id = ?1", nativeQuery = true)
    Long countByFollowed(String followedUser);


    // 現在ログインしているユーザーのフォローアップリストの照会
    @Query("SELECT f.followed FROM Follow f WHERE f.following = :userId")
    List<String> findFollowingByUserId(@Param("userId") String userId);

    // 現在ログインしているユーザーのフォロワー一覧を照会
    @Query("SELECT f.following FROM Follow f WHERE f.followed = :userId")
    List<String> findFollowersByUserId(@Param("userId") String userId);
}

上記のコードは、Follow Repositoryというインターフェースを定義したものです。 このインターフェースは、Followエンティティに対するデータベース作業を行うメソッドを定義しています。

findByFollowingAndFollowed
followingとfollowed値を基準にフォロー関係を照会するメソッドです。

countByFollowing
与えられたfollowing UserのEメールを基準に、そのユーザーをフォローする数を照会するメソッドです。

countByFollowed
与えられたfollowed UserのEメールを基準に、そのユーザーをフォローする数を照会するメソッドです。

findFollowingByUserId
与えられたuserIdをフォローするユーザーのメールリストを照会するメソッドです。

findFollowersByUserId
与えられたuserIdをフォローするユーザーのEメールリストを照会するメソッドです。

このように定義されたメソッドは、Spring Data JPAのJpaRepositoryインタフェースを継承しているため、当該インタフェースが提供する基本的なデータベース以外にもカスタムクエリを使用してデータを照会することができます。


3.4 Service - FollowService.java

@RequiredArgsConstructor
@Service
public class FollowService {

    private final FollowRepository followRepository;


    // フォロー要求を処理するサービスロジック
    @Transactional
    public String addFollow(String followingUser, String followedUser, Long id) {

        Follow follow = followRepository.findByFollowingAndFollowed(followingUser, followedUser);

        // 登録されたフォローがまだない場合
        if (follow == null) {

            follow = new Follow();
            follow.setFollowing(followingUser);
            follow.setFollowed(followedUser);
            followRepository.save(follow);

        } else {
            // 登録済みフォローの場合、失敗メッセージ
            return "もう登録されたフォローです。";
        }
        // フォロー登録時の成功メッセージ
        return "フォローが登録されたました。";
    }


    // アンフォロー要求を処理するサービスロジック
    @Transactional
    public String deleteFollow(String followingUser, String followedUser, Long id) {

        Follow follow = followRepository.findByFollowingAndFollowed(followingUser, followedUser);

        // 該当するフォローがあれば
        if (follow != null) {

            // アンフォローする
            followRepository.delete(follow);

        } else {

            // フォローがない場合はまだ登録されていないというメッセージを表示する
            return "まだ、フォローされていないです。";
        }
        // アンフォロー成功メッセージ
        return "フォローを削除しました。";
    }

    // ログインユーザーがフォローするユーザー数を計算する
    public Long getFollowingCount(String followingUser) {

        return followRepository.countByFollowing(followingUser);
    }

    // ログインユーザーをフォローするユーザー数を計算する
    public Long getFollowerCount(String followedUser) {

        return followRepository.countByFollowed(followedUser);
    }

    // ログインユーザーがフォローするユーザーリストを抽出する
    public List<String> getFollowing(String userId) {

        return followRepository.findFollowingByUserId(userId);
    }

    // ログインユーザーをフォローするユーザーリストを抽出する
    public List<String> getFollowers(String userId) {

        return followRepository.findFollowersByUserId(userId);
    }

    // ログインユーザーがフォローするユーザーリストでアンフォロー要求を処理する。
    @Transactional
    public String deleteFollowList(String followingUser, String followedUser) {

        Follow follow = followRepository.findByFollowingAndFollowed(followingUser, followedUser);

        // 該当するフォローがあれば
        if (follow != null) {

            // アンフォローする
            followRepository.delete(follow);

        } else {

            // フォローがない場合はまだ登録されていないというメッセージを表示する
            return "まだ、フォローされていないです。";
        }
        // アンフォロー成功メッセージ
        return "フォローを削除しました。";
    }
}

このクラスは、フォローとアンフォローに関連するビジネスロジックを処理するサービスです。

addFollow
フォローリクエストを処理するメソッドです。 following Userとfollowed Userを因子として受け取り、フォローしているかどうかを確認します。 もし、そのユーザーがすでにフォロー中の場合は「すでにフォロー中です」というメッセージを返し、そうでない場合は新しいフォローを登録します。 登録に成功すると、「フォロー登録が完了しました」というメッセージを返します。

deleteFollow
アンフォロー要求を処理するメソッドです。 followingUserとfollowedUserを因子として受け取り、アンフォローしているかどうかを確認します。 もしそのユーザーがフォローしている場合は、フォローを削除します。 フォローを削除した場合、「フォローがキャンセルされました」というメッセージを返し、フォロー中でない場合は「まだフォローしていません」というメッセージを返します。

getFollowingCount
ログインしたユーザーがフォローするユーザーの数を計算するメソッドです。 followingUserを因子として受け取り、そのユーザーがフォローする数をデータベースで照会して返します。

getFollowerCount
ログインしたユーザーをフォローするユーザーの数を計算するメソッドです。 followed Userを因子として受け取り、そのユーザーをフォローする数をデータベースで照会して返します。

getFollowing
ログインしたユーザーがフォローするユーザーのメールリストを照会するメソッドです。 userIdを因子として受け取り、そのユーザーがフォローするユーザーのメールリストをデータベースで照会して返します。

getFollowers
ログインしたユーザーをフォローするユーザーのメールリストを照会するメソッドです。 userIdを因子として受け取り、該当ユーザーをフォローするユーザーのメールリストをデータベースで照会して返します。

deleteFollowList
フォローリストからアンフォローするリクエストを処理するメソッドです。 followingUserとfollowedUserを因子として受け取り、該当ユーザーをフォロー中であることを確認し、フォロー中であればフォローを削除します。 削除に成功した場合、「フォローがキャンセルされました」というメッセージを返し、フォロー中でない場合は「まだフォローしていません」というメッセージを返します。

3.5 Controller - FollowController.java

@RestController
public class FollowController {

    private final FollowService followService;
    private final BlogService blogService;


    @Autowired
    public FollowController(FollowService followService, BlogService blogService) {
        this.followService = followService;
        this.blogService = blogService;
    }

    // フォロー要求処理
    @PostMapping("/follow/{id}")
    public String follow(@PathVariable Long id, Principal principal) {

        // スプリングセキュリティPrincipalからログインユーザー情報を抽出
        String followingUser = principal.getName();

        // 該当掲示物の作成者を探す
        String followedUser = blogService.findById(id).getAuthor();

        //フォローアップユーザーとフォロワーユーザーが両方いて、この2人が同じでなければ
         if (followingUser != null && followedUser != null && !followingUser.equals(followedUser)) {

             //フォローする
            return followService.addFollow(followingUser, followedUser, id);
        } else {
            return "フォローを失敗しました。";
        }
    }

    // アンフォロー要求処理
    @DeleteMapping("/unfollow/{id}")
    public String unfollow(@PathVariable Long id, Principal principal) {

        // スプリングセキュリティPrincipalからログインユーザー情報を抽出
        String followingUser = principal.getName();

        // 該当掲示物の作成者を探す
        String followedUser = blogService.findById(id).getAuthor();

        // フォローアップユーザーとフォロワーユーザーが両方いると
        if (followingUser != null && followedUser != null) {

            //アンフォローする
            return followService.deleteFollow(followingUser, followedUser, id);
        } else {
            return "アンフォローを失敗しました。";
        }
    }

    // ログインユーザーがフォローしているユーザー数の照会
    @GetMapping("/following-count")
    public Long getFollowingCount(Principal principal) {
        String followingUser = principal.getName();
        return followService.getFollowingCount(followingUser);
    }

    // ログインユーザーをフォローしているユーザー数の照会
    @GetMapping("/follower-count")
    public Long getFollowerCount(Principal principal) {
        String followedUser = principal.getName();
        return followService.getFollowerCount(followedUser);
    }

    // ログインしたユーザーのフォローアップリスト
    @GetMapping("/get-following/{userId}")
    public List<String> getFollowing(@PathVariable String userId) {
        return followService.getFollowing(userId);
    }

    // ログインしたユーザーのフォロワー一覧
    @GetMapping("/get-followers/{userId}")
    public List<String> getFollowers(@PathVariable String userId) {
        return followService.getFollowers(userId);
    }


    // フォローリスト中のアンフォロー要求処理
    @DeleteMapping("/list-unfollow/")
    public String unfollowList(@RequestBody Map<String, String> userId, Principal principal) {

        // スプリングセキュリティPrincipalからログインユーザー情報を抽出
        String followingUser = principal.getName();

        // リクエストから削除するフォローアップユーザーを抽出
        String followedUser = userId.get("userId");

        // フォローアップユーザーとフォロワーユーザーが両方いると
        if (followingUser != null && followedUser != null) {

            //アンフォローする
            return followService.deleteFollowList(followingUser, followedUser);
        } else {
            return "アンフォローを失敗しました。";
        }
    }
}


このクラスは、フォローとアンフォロー関連のリクエストを処理するRESTコントローラーです。ここで、注目すべきことは、「Principal」オブジェクトです。このオブジェクトでは現在認証されたユーザーの情報が含まれています。 つまり、現在ログインしているユーザーの情報を取得できます。 このオブジェクトは、ユーザーの認証情報を提供するためにSpring Securityによって自動的に生成され、コントローラのパラメータとして注入されます。

follow
文の作成者をフォローするリクエストを処理するメソッドです。 ユーザーは特定の文の作成者をフォローすることができ、そのために文のIDを経路変数として受け取ります。 Spring Security Principal オブジェクトを使用してログインしたユーザーの情報を抽出し、その書き込みの作成者をfollowed Userにインポートします。 フォローをするには、ログインしたユーザーと書き込みの作成者の両方が存在しなければならず、2人のユーザーは異なる電子メールでなければなりません。 この条件を満たすと、follow Serviceを通じてフォローを追加します。

unfollow
文の作成者をアンフォローするリクエストを処理するメソッドです。 ユーザーは特定の文の作成者をアンフォローすることができ、そのために文のIDを経路変数として受け取ります。 Spring Security Principal オブジェクトを使用してログインしたユーザーの情報を抽出し、その書き込みの作成者をfollowed Userにインポートします。 アンフォローをするには、ログインしたユーザーと書き込みの作成者の両方が存在する必要があります。 この条件を満たすと、フォローサービスを通じてアンフォローを実行します。

getFollowingCount
ログインしたユーザーがフォローするユーザーの数を照会するリクエストを処理するメソッドです。 Spring Security Principal オブジェクトを使用してログインしたユーザーの情報を抽出し、そのユーザーをフォローする数をfollow Serviceで照会します。

getFollowerCount
ログインしたユーザーをフォローするユーザーの数を照会するリクエストを処理するメソッドです。 Spring Security Principal オブジェクトを使用してログインしたユーザーの情報を抽出し、そのユーザーをフォローする数をfollow Serviceで照会します。

getFollowing
ログインしたユーザーがフォローするユーザーのメールリストを照会するリクエストを処理するメソッドです。 パス変数として与えられたuserIdを使用して、そのユーザーがフォローするユーザーのメールリストをfollowServiceで照会します。

getFollowers
ログインしたユーザーをフォローするユーザーのメールリストを照会するリクエストを処理するメソッドです。 経路変数として与えられたuserIdを使用して、そのユーザーをフォローするユーザーのメールリストをfollowServiceで照会します。

unfollowList
フォローリストからアンフォローするリクエストを処理するメソッドです。 リクエストの本文に含まれるuserIdを使用して、アンフォロー対象ユーザーを取得します。 Spring Security Principal オブジェクトを使用してログインしたユーザーの情報を抽出し、アンフォローを実行します。 ログインしたユーザーとアンフォロー対象ユーザーの両方が存在する必要があります。


3.6 Web API テスト - Postman

Postmanは、WebAPIテストツールの中で最も有名なものの 1 つです。 基本的なフォロー登録と削除をテストしてみるようにURLを書いて要請してみます。

follow

HTTPmethodを「POST」と設定後リクエストを送る
「200」メッセージの表示は成功を意味する
テーブルに登録された


unfollow

HTTPmethodを DELETEと設定後リクエストを送る
「200」メッセージの表示は成功を意味する
テーブルに削除された


3.7 フロントエンドのHttpRequest - follow.js

フロントエンド側でフォロー追加と削除要請をどのようにするのか重要な関数を中心に見てみましょう。

    // フォローボタンを押すとfollowHttpRequest呼び出し
    function addFollow(button) {
        const id = parseInt(button.dataset.itemId, 10);
        button.addEventListener('click', event => {
            body = JSON.stringify({});

            function success(response) {
                alert(response);
            };

            function fail(response) {
                alert(response);
            };
            followHttpRequest('POST', '/follow/' + id, body, success, fail)
        });
    }



    // アンフォローボタンを押すとfollowHttpRequest呼び出し
    function deleteFollow(button) {

        const id = parseInt(button.dataset.itemId, 10);
        button.addEventListener('click', event => {
            body = JSON.stringify({});

            function success(response) {
                alert(response);
            };

            function fail(response) {
                alert(response);
            };
            followHttpRequest('DELETE', '/unfollow/' + id, body, success, fail)
        });
    }

    // フォローリストでアンフォローボタンを押す時、followHttpRequest関数呼び出し
    function deleteListFollow(userId, popupContainer) {

        const body = JSON.stringify({
            userId: userId
        });

        function success(popupContainer, response) {
            alert(response);

            refreshFollowingList(); // 팔로잉 목록 새로고침
        };

        function fail(response) {
            alert(response);
        };
        followHttpRequest('DELETE', '/list-unfollow/', body, success(popupContainer), fail);
    }


addFollow(button)
この関数は、「フォロ」ボタンがクリックされたときに実行されます。 該当ボタンのデータ属性からアイテムIDを取得し、followHttpRequest関数を呼び出してPOST要求を送信します。 成功時にサーバーから受信した応答を通知として表示し、失敗時にも失敗メッセージを表示します。

deleteFollow(button)
この関数は、「アンフォロー」ボタンがクリックされたときに実行されます。 該当ボタンのデータ属性からアイテムIDを取得し、followHttpRequest関数を呼び出してDELETEリクエストを送信します。 成功時にサーバーから受信した応答を通知として表示し、失敗時にも失敗メッセージを表示します。

deleteListFollow(user Id, popup Container)
この関数は、フォローリストで「アンフォロー」ボタンがクリックされたときに実行されます。 該当ユーザーのIDに基づいて要求ボディをJSON形式で生成し、followHttpRequest関数を呼び出してDELETEリクエストを送信します。 成功時、サーバーから受け取った応答を通知として表示し、refreshFollowingList()関数を呼び出してフォローリストを更新します。 失敗時にも失敗メッセージを表示します。



4. テスト(08.03~08.04)


4.1 単体テスト

@BeforeEach
    public void mockMvcSetUp() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
                .build();
        followRepository.deleteAll();
    }

    @BeforeEach
    void setSecurityContext() {
        userRepository.deleteAll();
        user = userRepository.save(User.builder()
                .email("author1@gmail.com")
                .password("test")
                .build());

        SecurityContext context = SecurityContextHolder.getContext();
        context.setAuthentication(new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities()));
    }

    @DisplayName("follow: フォローアップ追加 成功")
    @Test
    public void follow() throws Exception {
        // given
        final Long articleId = 1L;
        final String following = "testuser1@gmail.com";
        final String followed = "author1@gmail.com";

        Principal principal = Mockito.mock(Principal.class);
        Mockito.when(principal.getName()).thenReturn(following);


        // when
        ResultActions result = mockMvc.perform(post("/follow/" + articleId)
                .contentType(MediaType.APPLICATION_JSON_VALUE)
                .principal(principal));

        // then
        result.andExpect(status().is2xxSuccessful());
        List<Follow> follows = followRepository.findAll();

        assertThat(follows.size()).isEqualTo(1);
        assertThat(follows.get(0).getFollowing()).isEqualTo(following);
        assertThat(follows.get(0).getFollowed()).isEqualTo(followed);

    }

    @DisplayName("unfollow: アンフォロー成功")
    @Test
    public void unfollow() throws Exception {
        // given
        final Long articleId = 1L;
        final String following = "testuser1@gmail.com";
        final String followed = "author1@gmail.com";

        Principal principal = Mockito.mock(Principal.class);
        Mockito.when(principal.getName()).thenReturn(following);


        // when
        ResultActions result = mockMvc.perform(delete("/unfollow/" + articleId)
                .contentType(MediaType.APPLICATION_JSON_VALUE)
                .principal(principal));

        // then
        result.andExpect(status().is2xxSuccessful());
        List<Follow> follows = followRepository.findAll();
        assertThat(follows).isEmpty();
    }

    @DisplayName("unfollowList: フォロワーリストからアンフォロー成功")
    @Test
    public void unfollowList() throws Exception {
        // given
        final String following = "testuser1@gmail.com";
        final String followed = "author1@gmail.com";

        Principal principal = Mockito.mock(Principal.class);
        Mockito.when(principal.getName()).thenReturn(following);

        // Request Bodyに伝えるデータ構成(JSON形式でマップを生成)
        Map<String, String> requestBody = new HashMap<>();
        requestBody.put("userId", followed);


        // when
        ResultActions result = mockMvc.perform(delete("/list-unfollow/")
                .contentType(MediaType.APPLICATION_JSON)
                .content(asJsonString(requestBody))
                .principal(principal));

        // then
        result.andExpect(status().isOk());

        // Followオブジェクトが削除されたか確認
        List<Follow> follows = followRepository.findAll();
        assertThat(follows).isEmpty();


    }

    private String asJsonString(Object obj) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        return mapper.writeValueAsString(obj);

    }

単体テスト テストのためにJunitとMockMvcを使用してAPI要求を行い、予想結果を検証します。

MockMvcはスSpringフレームワークのWebアプリケーションテストのための模擬オブジェクト(Mock)を使用するクラスです。 これを使用して、Web アプリケーションのControllerをテストし、リクエストと応答するテスト コードを作成できます。

基本的にテストコードは「given」、「when」、「 then」  の順番でテストコードを作成しました。「given」はデータ、オブジェクトなどの準備です。「when」は実行、「then」は結果を意味します。

followテスト
フォロー機能が正常に動作するか確認します。 与えられたarticleIdに該当する文をフォローする要請を送り、結果としてHTTP 2xx応答を受けてくるか検証し、フォローオブジェクトがデータベースに保存されているかを確認します。

unfollowテスト
アンフォロー機能が正常に動作するか確認します。 与えられたarticleIdに該当する文をアンフォローする要請を送り、結果としてHTTP 2xx応答を受けてくるか検証し、データベースにフォローオブジェクトが削除されたかを確認します。

unfollowListテスト
フォロワーリストでアンフォロー機能が正常に動作するか確認します。 要求ボディにフォローを取り消すユーザーのuserIdをJSON形式で含めてリクエストを送り、結果としてHTTP 200 OK応答を受けてくるか検証し、データベースにフォローオブジェクトが削除されたかを確認します。

各テストは、与えられた機能が予想通りに動作することを確認し、アプリケーションのフォロー機能が正確に実装されているかどうかを検証します。

やった、テストの結果がうまくいきました!

 JUnitの単体テスト結果


4.2 結合テスト

1. フォロー中を確認する
2.「見る」ボタンを押す
3. 「フォロー」ボタンを押す
登録成功のメッセージが表示される
フォロー中を確認すると数が増えた
4. 青い数を押す
フォロー中のユーザーのリストが表示される
5. 青い「アンフォロー」ボタンを押す
アンフォロー成功のメッセージが表示される
フォロー中を確認すると数が減らした
6. 「user5@gmail.com」が作成した記録で「アンフォロ」する
アンフォロー成功のメッセージが表示される
フォロー中の数がまた減らした
7.フォロワーの青い数を押す
フォロワーのリストが表示される
8.「以後」ボタンをおす
5名づつリストがページネーションされる


これによりフォロー登録、フォロー削除(アンフォロー)、フォロー数、フォロワー数、フォローリストからフォロー削除(アンフォロー)、フォロー/フォロワーページネーション機能が正常に動作することを確認しました。

5. まとめ


フォロー機能の設計からバックエンドとフロントエンドの実装、そしてテストまで7月26日から8月4日まで8日かかりました。 計画上は8月3日までに終わらせようとしましたが、予定より一日遅れてしまいました! 実は掲示板の登録と修正削除機能の応用だとしても、やはり応用には時間がかかってしまいます。 十分に技術を身につけるまで頑張らないといけませんね!
これまで作ったフォロー機能は、ログインしたユーザーが誰に興味があり、自分も誰の関心を集めているかが分かり、早起きに強力な一次的モチベーションを受けられると期待されています。 それでは今まで実現したフォロー機能をもとに、8月14日までに「いいね」機能に発展させてみます。


エンジニアファーストの会社 株式会社CRE-CO
ソンさん


この記事が気に入ったらサポートをしてみませんか?