[Unit Test] Software Testing

김상웅·2022년 7월 14일
0

[파이썬]

목록 보기
17/17

✅ 들어가면서


코딩만 잘하는 개발자는 살아남지 못하는 시대가 다가오고 있습니다.

개발자도 결국 서비스를 제공하는 직업군입니다.

만약 우리가 만든 웹가 앱이 배포된 이후에 여러 문제가 발생한다면, 우리의 웹과 앱은 시장가치가 떨어질 것이고, 결국 경쟁에서 뒤쳐질 것 입니다.

전자기기, 가전제품 등 소비자에게 도달하기 전에 안전성 테스트, 결함 여부 확인 등 수많은 절차와 시험을 거칩니다.

개발자인 우리도 마찬가지로 우리가 만든 서비스 (웹이든 앱이든)에 문제는 없는지 확인을 해야하는 단계를 거쳐야 하는데요.

그 과정을 소프트웨어 테스트, 코드 테스트 .. 즉 테스트 단계를 가리킵니다.



✅ Software Testing


📌 개념

서비스를 배포하기 위해 우선 코드를 작성합니다.

우리는 코드를 작성하면서 그 결과를 예상할 수 있습니다.

예상 결과를 도출하였다면 그 결과가 올바른지 확인을 해야합니다.

테스트를 하는 방법에는 3가지로 나눌 수 있는데 우선은 코드를 통한 테스트로 가정해봅시다.

개발자는 다시 테스트 코드를 작성하고 이 코드를 통해 실제 서비스를 구현하는 코드를 테스트합니다.

이 테스트 코드를 실행한 결과가 성공했다면 테스트는 완료된 것입니다.

만약 실패하면 코드를 수정하거나 버그를 고쳐야겠죠.

개발을 하면서 수많은 딜레마에 빠지게 될 것입니다.

제대로 된 소프트웨어를 개발했는가?
소프트웨어를 제대로 개발했는가?

코드를 위한 코드를 작성하는 것이 아닌,
실제 서비스를 제공하는 입장에서 다양하고 꼼꼼한 테스트 코드를 통해 우리의 코드를 제대로 작성하는 것의 중요성을 되짚어 봐야될 것 같습니다.


📌 왜

그렇다면, 이 테스트를 왜 하는 것일까요?

간단하게 알아봅시다.

  1. 시중에 내놓기 전 결함을 확인할 수 있습니다.

  2. 결함을 사전에 방지할 수 있습니다.

  3. 시간을 절약할 수 있습니다. (재설계시간 등)

  4. 구조를 개선할 수 있습니다.

  5. 품질을 개선할 수 있습니다.

  6. 확장성이 용이해집니다.



✅ Manual Testing


테스트의 종류 중 하나로 수동 테스트, 즉 사람이 직접 일일히 기능을 테스트 해보는 방법입니다.

일련의 모든 내용을 하나씩 사용해보면서 UI/UX를 직접 확인하는 방법을 가리킵니다.

하지만 사람이 하는 모든 일에는 실수가 있을 수 있습니다.

불안정성과 같은 문제가 발생할 수 있다는 것이죠.

또 테스트를 해야되는 인력이 필요합니다.

물론 속도도 더디게되겠죠.

그렇기 때문에 물적, 인적, 시간적인 측면에서 비용이 늘어나는 문제점이 있습니다.



✅ Automation Testing


우리가 1000명의 직원들의 4월 월급을 계산해야한다고 가정해봅시다.

보통은 계산기로 두드리자 않고 엑셀의 함수를 통해 계산을 할 것입니다.

계산기로 두드리는 것보다 엑셀의 셀을 끌어 월급을 한번에 계산하면 정말 효율적이겠죠.

소프트웨어 테스트도 마찬가지입니다.

자동화 테스트를 했을 때의 이점은 다음과 같습니다.

  1. 안정성이 증대됩니다.

  2. 반면, 인력 소모는 줄어듭니다.. (이건 좀 아쉽지만, 우린 개발자이기 때문에..!)

  3. 비용이 감소합니다.

  4. 테스트 속도가 월등히 빨라집니다.

  5. 확장성이 증대됩니다.



✅ 시스템 테스트 전략 3가지


우리는 이번 포스팅에서 계속 소프트웨어 테스트에 대해 이야기하고 있습니다.

이번에는 어떤 전략이 있는지 알아보겠습니다.


📌 end to end test

이름에서 알 수 있듯 프론트엔드와 백엔드 간 통신을 통해 테스트하는 것을 의미합니다.

전체적인 흐름(flow)을 확인할 수 있습니다.

프론트엔드 개발자들에겐 cypress를 활용한 테스트가 익숙하실 것입니다.

End to End 테스트 비중은 보통 10%로 권장합니다.


📌 integration test

모듈간의 호환성을 검증하는 테스트 단계입니다.

프론트엔드와 백엔드 디렉토리에서 작성된 모듈을 각각 통합 (integration)하여 테스트하는 방법을 떠올리면 됩니다.

외부 모듈을 통해 코드들을 확인할 수 있는데요.

백엔드 개발자들에겐 httpie포스트맨을 활용한 테스트 방식이 익숙하실 것입니다.

integreation test 비중은 20%로 권장합니다.


📌 Unit Test

마지막으로 유닛테스트입니다.

단어만 들어도 굉장히 작은 단위의 테스트를 진행할 것이다라는 느낌이 오는데요.

독립적으로 진행되는 가장 작은 단위의 테스트를 가리킵니다.

가장 작은 단위는 프로젝트마다 상이하겠지만, 하나의 기능 또는 메서드를 가리킵니다.

테스트 비중은 70%로 권장될 만큼 매우 중요한 테스트 단계입니다.

그 이유는 다음과 같습니다:

  1. 빠르게 (코드의) 문제를 파악할 수 있습니다.

  2. 시간과 비용을 절약할 수 있습니다.

  3. 안정성이 확보된 상태로 리팩토링을 진행할 수 있습니다.

  4. 코드에 대한 문서로 활용됩니다.
    백엔드의 경우 API 시스템을 테스트 코드로 확인할 수 있습니다.


테스트 코드를 먼저 작성하고 API를 확장시키는 개발 문화도 있다!

서비스를 위한 코드보다 그 코드를 테스트하는 코드가 더 중요하다고 말하는 개발자도 있습니다.
그런 문화가 점차 발전하고 있으며, 서비스를 제공하는 입장에서 어떤 테스트를, 어떤 결과물을 도출하는지 예측하고 그림을 그릴 수 있는 개발자로 성장해야겠습니다.



✅ 테스트의 일반 원칙


이제 Unit Test에 대해 좀 더 자세히 알아볼텐데요.

우리가 작성한 코드를 다시 우리가 작성한 코드로 테스트하는 것이라고 설명했습니다.

Unit Test를 작성하면서 지켜야 할 원칙들이 있는데요.

  1. 유닛은 각 기능의 가장 작은 단위에 집중하며 해당 기능이 정확히 동작하는지를 증명해야합니다.

앞서 설명드렸듯이 가장 작은 단위는 하나의 기능 또는 메서드를 가리키겠죠

  1. 각 테스트 유닛은 반드시 독립적이어야 합니다.

다음 주제에서 알아볼 내용인데요.

유닛 테스트 코드를 작성하면서 새로운 데이터 셋으로 각각의 테스트를 로딩하고 그 실행 결과를 삭제해주는 작업을 진행해야 합니다.

보통 setUp()tearDown() 메서드가 이런 작업을 담당하고 있습니다.

  1. 테스트가 빠르게 돌 수 있도록 만들기 위해 노력해야합니다.

테스트 하나가 실행하는데 일정 밀리세컨드 이상의 시간이 소요되면 개발 속도가 지체되고 테스트가 충분히 실행되지 못할 것입니다.

데이터 셋을 매번 생성해야하는 경우가 있을 텐데요.

그럴 때는 별도의 테스트 슈트를 만들어 필요한 테스트에서 사용할 수 있습니다.

  1. 개발 시작 전/후로 풀 테스트 슈트를 실행해야 합니다.

개발 시작 전의 코드가 문제가 없는지 확인할 수 있고,

개발을 마치고 난 후의 코드의 문제 여부도 확인할 수 있습니다.

  1. 가장 먼저 시작할 일은 버그를 찝어내는 새로운 테스트를 작성해야합니다.
  1. 테스트 함수에는 길고 서술적인 이름을 사용해야합니다.

함수의 이름은 a() abc()로 작성해도 작동이 잘될 것입니다.

하지만 테스트 함수는 절대 직접 호출되지 않습니다.

그렇기 때문에 테스트 코드에서는 다음과 같이 어떤 테스트를 진행하는지 자세한 이름을 지어줘야 합니다.
예시))) test_success_user_sign_in_post(), test_fail_decede_error_of_token() 등..

이런 함수는 테스트를 실패하였을 때 볼 수 있습니다. 다음 사진처럼 말이죠.

테스트 코드는 팀에 새로 합류한 개발자들을 위한 안내서로도 사용됩니다.

이미 만들어져 있는 코드에서 작업해야하는 경우 테스트 코드를 돌려보고 읽어보는 것을 통해 어떤 개발을 하고 있었는지 파악할 수 있게됩니다.



✅ Back-end Testing


가벼운 예시를 통해 백엔드 유닛테스트에 대해 알아보겠습니다!

저는 Django 프레임워크를 사용하여 백엔드 서버를 개발 중이기 때문에
Django 위주의 테스트 코드를 예시로 들어보겠습니다.

아래의 코드는 유저의 정보를 불러오는 테스트 코드입니다:

from users.models import User # User 클래스(테이블)를 불러옵니다.

from django.test import TestCase # Django >> 인자로 TestCase만 입력

class MyCalcTest(TestCase):
    def setUp(self):
        # 가상 데이터베이스에 유저의 정보를 생성해주세요.
        # 여기서 생성되는 데이터는 우리가 이미 갖고 있는 데이터베이스를 가리킵니다.
        User.ojbects.create(
        	id       = 1,
            name     = "sangwoong",
            account  = "sangwoong",
            password = "1234",
        )
        
    def tearDown(self):
        # 테스트의 독립성을 유지하기 위해 생성된 가상의 데이터를 삭제해줍니다.
        User.objects.all().delete()
        
    def test_success_get_user_info(self):
    	# 테스트를 진행하여 실제 결과와 비교하는 함수입니다.
    	client   = Client()
        response = client.get("/users/1")
        
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json(), {
        	"results" = {
            	"id"      : 1,
                "name"    : "sangwoong",
                "account" : "sangwoong"
            }
        }

setUp 함수에는 테스트를 할 수 있게끔 데이터를 넣어주는 단계입니다.
Django 프레임워크는 테스트 함수를 실행하면서 가상의 데이터베이스를 생성하여 우리가 작성한 데이터를 임시적으로 생성하여줍니다.

여기서 생성한 데이터는 우리가 테스트하려는 코드의 데이터베이스가 되니, 필요한 데이터를 작성해주면 됩니다.

tearDown은 테스트를 통해 생성한 데이터를 초기화하는 단계입니다.

마찬가지로 실제 데이터베이스를 사용하지 않습니다.

서비스를 개발할 때 수많은 유닛 테스트가 존재하기 때문에 각각의 독립성을 유지하기 위해 두 함수를 거치게됩니다.

test_... 실제 테스트를 진행하여 예상되는 결과와 비교하는 함수입니다.

client = Client()라는 코드를 통해 실제 서버를 켜놓은 것처럼 작동하게 해줍니다.

우리가 views.py에 작성한 코드의 예상 결과와 일치하는지 확인할 수 있습니다.

테스트코드를 실행하였을 때 발생하는 에러를 통해 우리가 작성한 코드에 버그와 오류를 잡을 수 있고,

우리가 작성한 코드에 확신을 갖고 개발할 수 있겠습니다.

profile
누구나 이해할 수 있도록

0개의 댓글