TIL/Django

[Django] Channels 사용하기 - 4

oraange 2022. 10. 24. 17:31

이 글은 [Django] Channels 사용하기 - 3에서 이어집니다.

views 테스트하기

Selenium을 사용하여 end-to-end 테스트를 할 것이다.

  • 메시지를 보낼 때, 같은 방에 있는 모두가 그 메시지를 보는가
  • 메시지를 보낼 떄, 다른 방에 있는 누군가는 메시지를 볼 수 없는가

Selenium을 설치하자

$ python3 -m pip install selenium

chat/tests.py 파일을 만들고 코드를 작성하자.

# chat/tests.py
from channels.testing import ChannelsLiveServerTestCase
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys # 키보드의 키 명령 모음
from selenium.webdriver.support.wait import WebDriverWait


class ChatTests(ChannelsLiveServerTestCase):
    serve_static = True # emulate StaticLiveServerTestCase

    @classmethod
    def setUpClass(cls):
    """
    Set up configuration
    """
        super().setUpClass()
        try:
            # NOTE: Requires "chromedriver" binary to be installed in $PATH
            cls.driver = webdriver.Chrome("chromedriver가 깔린 path 입력")
        except:
            super().tearDownClass()
            raise

    @classmethod
    def tearDownClass(cls) -> None:
    """
    Delete configuration
    """
        cls.driver.quit()
        super().tearDownClass()

    def test_when_chat_message_posted_then_seen_by_everyone_in_same_room(self):
        try:
            self._enter_chat_room("room_1")

            self._open_new_window()
            self._enter_chat_room("room_1")

            self._switch_to_window(0)
            self._post_message("hello")
            WebDriverWait(self.driver, 2).until(
                lambda _: "hello" in self._chat_log_value,
                "Message was not received by window 1 from window 1",
            )

            self._switch_to_window(1)
            WebDriverWait(self.driver, 2).until(
                lambda _: "hello" in self._chat_log_value,
                "Message was not received by window 2 from window 1",
            )
        finally:
            self._close_all_new_windows()

    def test_when_chat_message_posted_then_not_seen_by_anyone_in_different_room(self):
        try:
            self._enter_chat_room("room_1")

            self._open_new_window()
            self._enter_chat_room("room_2")

            self._switch_to_window(0)
            self._post_message("hello")
            WebDriverWait(self.driver, 2).until(
                lambda _: "hello" in self._chat_log_value,
                "Message was not received by window 1 from window 1",
            )

            self._switch_to_window(1)
            self._post_message("world")
            WebDriverWait(self.driver, 2).until(
                lambda _: "world" in self._chat_log_value,
                "Message was not received by window 2 from window 2",
            )
            self.assertTrue(
                "hello" not in self._chat_log_value,
                "Message was improperly received by window 2 from window 1",
            )
        finally:
            self._close_all_new_windows()

    # === Utility ===

    def _enter_chat_room(self, room_name):
        self.driver.get(self.live_server_url + "/chat/")
        ActionChains(self.driver).send_keys(room_name, Keys.ENTER).perform()
        WebDriverWait(self.driver, 2).until(
            lambda _: room_name in self.driver.current_url
        )

    def _open_new_window(self):
        self.driver.execute_script('window.open("about:blank", "_blank");')
        self._switch_to_window(-1)

    def _close_all_new_windows(self):
        while len(self.driver.window_handles) > 1:
            self._switch_to_window(-1)
            self.driver.execute_script("window.close();")
        if len(self.driver.window_handles) == 1:
            self._switch_to_window(0)

    def _switch_to_window(self, window_index):
        self.driver.switch_to.window(self.driver.window_handles[window_index])

    def _post_message(self, message):
        ActionChains(self.driver).send_keys(message, Keys.ENTER).perform()

    @property
    def _chat_log_value(self):
        return self.driver.find_element(
            by=By.CSS_SELECTOR, value="#chat-log"
        ).get_property("value")

django에서는 테스트를 위한 데이터베이스로 in-memory 데이터베이스인 sqlite3를 사용하고 있으므로 테스트가 잘 실행되지 않을 것이다. 따라서 테스트를 실행하기 위해 sqlite3 데이터베이스가 메모리에 있을 필요가 없다고 프로젝트에 알려야 한다. socket_channels/settings.py에 다음과 같이 수정하자.

# socket_channels/settings.py
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.sqlite3",
        "NAME": BASE_DIR / "db.sqlite3",
        "TEST": {
            "NAME": BASE_DIR / "db.sqlite3",
        },
    }
}

이제 테스트를 실행해 보자.

$ python3 manage.py test chat.tests

 

반응형