Esempio n. 1
0
    def __post_init__(self):
        # Pythonのデフォルト引数の罠を踏まないための実装
        if self.execute_date is None:
            self.execute_date = datetime.datetime.today()

        self.__dummy_reservation = Reservation(self._get_next_reservation_id(),
                                               self._default_time_to_range(),
                                               NumberOfParticipants(4),
                                               MeetingRoomId('A'),
                                               EmployeeId('001'))
Esempio n. 2
0
 def reservation(self) -> Reservation:
     """不正でないReservationインスタンスを作成するだけのfixture"""
     return Reservation(
         ReservationId(str(uuid.uuid4())),
         TimeRangeToReserve(使用日時(2020, 4, 2, 13, 00),
                            使用日時(2020, 4, 2, 14, 00)),
         NumberOfParticipants(4), MeetingRoomId('A'), EmployeeId('001'))
    def test_単一の正常なReservationを生成できる_予約時間帯は翌日13時から14時がデフォルトとなる(self):
        expected = Reservation(
            ReservationId('1'),
            TimeRangeToReserve(使用日時(2020, 4, 2, 13, 00),
                               使用日時(2020, 4, 2, 14, 00)),
            NumberOfParticipants(4), MeetingRoomId('A'), EmployeeId('001'))

        assert DummyReservationBuilder().build() == expected
    def to_reservation(cls, source: OratorReservationModel) -> Reservation:
        start_yyyy_mm_dd_HH_MM = datetime.datetime.strptime(
            source.start_datetime, '%Y-%m-%d %H:%M:%S').timetuple()[:5]
        end_yyyy_mm_dd_HH_MM = datetime.datetime.strptime(
            source.end_datetime, '%Y-%m-%d %H:%M:%S').timetuple()[:5]
        time_range_to_reserve = TimeRangeToReserve(
            使用日時(*start_yyyy_mm_dd_HH_MM), 使用日時(*end_yyyy_mm_dd_HH_MM))

        return Reservation(
            ReservationId(source.id), time_range_to_reserve,
            NumberOfParticipants(source.number_of_participants),
            MeetingRoomId(source.meeting_room_id),
            EmployeeId(source.reserver_id),
            ReservationStatus.from_str(source.reservation_status))
Esempio n. 5
0
    def test_Reservationが作れるよ(self):
        reservation_id = 'データクラス同士の比較のために、やっているよ'

        actual = self.reservation_factory.create(date='20200402',
                                                 start_time='1100',
                                                 end_time='1300',
                                                 meeting_room_id='A',
                                                 reserver_id='001',
                                                 number_of_participants='5',
                                                 reservation_id=reservation_id)

        expected = Reservation(
            ReservationId(reservation_id),
            TimeRangeToReserve(使用日時(2020, 4, 2, 11, 00),
                               使用日時(2020, 4, 2, 13, 00)),
            NumberOfParticipants(5), MeetingRoomId('A'), EmployeeId('001'))

        assert actual == expected
    def test_複雑なReservationもメソッドチェーンでつくりやすいよ(self):
        another_time_range_to_reserve = TimeRangeToReserve(
            使用日時(2020, 4, 15, 13, 00), 使用日時(2020, 4, 15, 14, 00))
        another_meeting_room_id = MeetingRoomId('Z')
        another_employee_id_999 = EmployeeId('999')

        expected = Reservation(ReservationId('1'),
                               another_time_range_to_reserve,
                               NumberOfParticipants(4),
                               another_meeting_room_id,
                               another_employee_id_999,
                               ReservationStatus.Canceled)

        actual = DummyReservationBuilder() \
            .with_time_range_to_reserve(another_time_range_to_reserve) \
            .with_meeting_room_id(another_meeting_room_id) \
            .with_reserver_id(another_employee_id_999) \
            .with_cancel() \
            .build()

        assert actual == expected
Esempio n. 7
0
    def create(
        self,
        date: str,
        start_time: str,
        end_time: str,
        meeting_room_id: str,
        reserver_id: str,
        number_of_participants: str,
        reservation_id: str = str(uuid.uuid4())
    ) -> Reservation:

        reservation_id = self._create_reservation_id(reservation_id)
        time_range_to_reserve = self._create_time_range_to_reserve(
            date, end_time, start_time)
        number_of_participants = self._create_number_of_participants(
            number_of_participants)
        meeting_room_id = self._create_meeting_room_id(meeting_room_id)
        employee_id = self._create_employee_id(reserver_id)

        return Reservation(reservation_id, time_range_to_reserve,
                           number_of_participants, meeting_room_id,
                           employee_id)
Esempio n. 8
0
class DummyReservationBuilder:
    """テスト用のReservation生成を楽にするためのクラス

    テスト以外では使ってはいけない理由
        1. 不正なReservationをつくれてしまうから
            - 存在しない会議室IDや存在しない予約者IDを持つReservationの生成ができてしまう
        2. Reservation間の整合性(予約時間帯が重なっていないなど)は担保できないから
            - やろうと思えば、リポジトリやドメインサービスを適用するってことはできるが、それはやりすぎでは?

    ポイント
        1. デフォルトの予約時間帯は、「実行日の翌日の13時〜14時」である
            - `time_range_to_reserve` の指定記述が非常にだるいのでこれで十分という判断
            - 「翌日」にしているのは、不正な予約時間帯になるのを防ぐため
            - 特定の予約時間帯で作りたい場合は、 `self.with_time_range_to_reserve()` を使いましょう

    できないこと
        1. 過去の日時を持つデータはつくれない
            - 結局、使用日時クラスの now で判断しているため生成不可能。freezegunなどで日時を固定すること
        2. reservation_id と number_of_participants の指定はできない(2020年6月1日時点)
            - 現状、これらを特定の値にしたいモチベーションがないため

    その他
        1. 同一のインスタンスから生成されるReservationのId重複だけは防いでいる
    """
    execute_date: datetime.date = dataclasses.field(default=None)
    used_reservation_ids: Set[ReservationId] = dataclasses.field(default_factory=set)
    __dummy_reservation: Reservation = dataclasses.field(init=False)

    def __post_init__(self):
        # Pythonのデフォルト引数の罠を踏まないための実装
        if self.execute_date is None:
            self.execute_date = datetime.datetime.today()

        self.__dummy_reservation = Reservation(self._get_next_reservation_id(),
                                               self._default_time_to_range(),
                                               NumberOfParticipants(4),
                                               MeetingRoomId('A'),
                                               EmployeeId('001'))

    def _get_next_reservation_id(self) -> ReservationId:
        """次のReservationIdを生成する。Idの値は1から順にインクリメントする。"""
        # これを採用したメリット: Reservationインスタンスのassertionが楽にできる
        # これを採用したリスク: インスタンスを複数つくれば、ReservationIdかぶりをつくれる

        used_id_count = len(self.used_reservation_ids)
        next_id = str(used_id_count + 1)

        return ReservationId(next_id)

    def _default_time_to_range(self) -> TimeRangeToReserve:
        """実行日の翌日13時〜14時 がデフォルトの予約時間帯"""
        the_next_day = self.execute_date + datetime.timedelta(days=1)
        yyyy, mm, dd, *_ = the_next_day.timetuple()

        return TimeRangeToReserve(使用日時(yyyy, mm, dd, 13, 00),
                                  使用日時(yyyy, mm, dd, 14, 00))

    def with_meeting_room_id(self, meeting_room_id: MeetingRoomId) -> DummyReservationBuilder:
        # テストデータ作成のための強引なミューテーション
        self.__dummy_reservation = dataclasses.replace(self.__dummy_reservation, meeting_room_id=meeting_room_id)

        return self

    def with_cancel(self) -> DummyReservationBuilder:
        self.__dummy_reservation = self.__dummy_reservation.cancel()

        return self

    def with_reserver_id(self, reserver_id: EmployeeId) -> DummyReservationBuilder:
        # テストデータ作成のための強引なミューテーションだから妥協して使用している
        self.__dummy_reservation = dataclasses.replace(self.__dummy_reservation, reserver_id=reserver_id)

        return self

    def with_time_range_to_reserve(self, time_range_to_reserve: TimeRangeToReserve) -> DummyReservationBuilder:
        # テストデータ作成のための強引なミューテーションだから妥協して使用している
        self.__dummy_reservation = dataclasses.replace(self.__dummy_reservation,
                                                       time_range_to_reserve=time_range_to_reserve)

        return self

    def with_random_id(self) -> DummyReservationBuilder:
        # テストデータ作成のための強引なミューテーションだから妥協して使用している
        # ReservationId の生成ルールがガードできていないので注意!
        self.__dummy_reservation = dataclasses.replace(self.__dummy_reservation, id=ReservationId(str(uuid.uuid4())))

        return self

    def build(self) -> Reservation:
        if self._has_already_build_reservation_id():
            self._set_next_id()

        self._register_used_id()

        return self.__dummy_reservation

    def _has_already_build_reservation_id(self) -> bool:
        return self.__dummy_reservation.id in self.used_reservation_ids

    def _set_next_id(self) -> None:
        self.__dummy_reservation = dataclasses.replace(self.__dummy_reservation, id=self._get_next_reservation_id())

    def _register_used_id(self) -> None:
        self.used_reservation_ids.add(self.__dummy_reservation.id)