์ํํธ์จ์ด ํ ์คํธ๋ ์ํํธ์จ์ด ๊ฐ๋ฐ ํ๋ก์ธ์ค์ ์ค์ํ ๋จ๊ณ๋ก์, ๊ฐ๋ฐ๋ ์ํํธ์จ์ด๊ฐ ๋ชฉํ์ ๋ถํฉํ๋ฉฐ ์์ ์ ์ด๊ณ ํจ์จ์ ์ผ๋ก ๋์ํ๋์ง๋ฅผ ํ์ธํ๊ธฐ ์ํ ๊ณผ์ ์ ๋๋ค. ํ ์คํธ๋ ๋ฒ๊ทธ๋ฅผ ์ฐพ๊ณ ์์ ํ๋ฉฐ, ์ํํธ์จ์ด์ ํ์ง์ ํฅ์์ํค๊ณ ์ฌ์ฉ์์๊ฒ ์ ๋ขฐ์ฑ ์๋ ์ ํ์ ์ ๊ณตํ๋ ๋ฐ ๋์์ ์ค๋๋ค.
ํจ์์ ์ด๋ค ์ ๋ ฅ์ด ์ฃผ์ด์ก์๋ ๊ธฐ๋ํ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค์ด ๋ด๋์ง์ ๊ฐ์ ๊ฐ๋จํ ํ ์คํธ๋ถํฐ ํ ๋ฒ์ ์ฌ๋ฌ ์ฌ์ฉ์๊ฐ ์ ์ํ ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ ์ฒ๋ฆฌํ๋ ๊ฒ ๊น์ง ๋ค์ํ ํ ์คํธ๊ฐ ์์ต๋๋ค. ํ ์คํธ๋ฅผ ์ํํ๋ ๊ฒ์ ๋ฒ๊ทธ๊ฐ ์ฌ๋ฐํ๋ ๊ฒ์ ๋ฐฉ์งํ๊ณ , ์ดํ ๋ฆฌํฉํ ๋ง ๊ณผ์ ์์ ์๊ฐ์ ์ ์ฝํด์ค ์ ์์ต๋๋ค.
[ ํ
์คํธ์ ์ข
๋ฅ ] - ๋จ์ ํ ์คํธ(Unit Testing): ๊ฐ๋ณ ๋ชจ๋ ๋๋ ํจ์๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋์ง ํ์ธํ๋ ํ ์คํธ์ ๋๋ค. - ํตํฉ ํ ์คํธ(Integration Testing): ๊ฐ ๋ชจ๋์ด ๊ฒฐํฉ๋์ด ์ ์ฒด ์์คํ ์ด ์์๋๋ก ์๋ํ๋์ง ํ์ธํ๋ ํ ์คํธ์ ๋๋ค. - ์์คํ ํ ์คํธ(System Testing): ์ ์ฒด ์์คํ ์ด ์ฌ์ฉ์์ ์๊ตฌ ์ฌํญ์ ์ถฉ์กฑ์ํค๊ณ ์์๋๋ก ์๋ํ๋์ง ํ์ธํ๋ ํ ์คํธ์ ๋๋ค. - ์ธ์ ํ ์คํธ(Acceptance Testing): ์ต์ข ์ฌ์ฉ์ ๋๋ ๊ณ ๊ฐ์ด ์์คํ ์ ๊ธฐ๋ฅ ๋ฐ ์ฑ๋ฅ์ ํ์ธํ๋ ํ ์คํธ์ ๋๋ค. |
์ด๋ฒ ๊ฒ์๊ธ์์๋ ๊ฐ๋จํ ๋จ์ ํ ์คํธ์ ํตํฉ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํฉ๋๋ค. ํ์ด์ฌ ๋ด์ฅ ํจํค์ง์ธ unittest๋ฅผ ์ด์ฉํ์ฌ ํ ์คํธ๋ฅผ ์์ฑํด๋ณด๊ณ , ๋ง์ง๋ง์๋ ์ข ๋ ์ฌ์ฉํ๊ธฐ ํธ๋ฆฌํ pytest๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ๋ ์์๋ด ๋๋ค.
๋จ์ ํ ์คํธ(unit testing)
๋จ์ ํ ์คํธ๋ ์ํํธ์จ์ด์ ๋ชจ๋ ์์ ๋ถ๋ถ๋ค์ด ๋์ํ๋์ง๋ฅผ ํ์ธํ๊ณ , ์๋ํฌ์๋ ํ ์คํธ ๊ฐ์ ๋๊ท๋ชจ ํ ์คํธ๋ฅผ ์ํ ํ ๋๋ฅผ ๋ง๋ จํด์ค๋๋ค. ๋ชจ๋ ๊ฐ๋ณ ์ฝ๋ ๋จ์๊ฐ ์์ํ๋๋ก ์๋ํ๋์ง ๊ฒ์ฌํ ์ ์์ต๋๋ค.
ํ์ด์ฌ์ ๋ด์ฅ๋ unittest๋ก ํ ์คํธ๋ฅผ ์ํํ ์ ์์ต๋๋ค. ํฐ๋ฏธ๋์ `python -m unittest`๋ผ๊ณ ์ ๋ ฅํ๋ฉด ํ ์คํธ๋ฅผ ์คํํ ์ ์์ผ๋ฉฐ ์๋์ ๊ฐ์ ๊ณผ์ ์ผ๋ก ํ ์คํธ๊ฐ ์งํ๋ฉ๋๋ค.
1. ํ์ฌ ๋๋ ํฐ๋ฆฌ ๋ฐ ํ์ ๋๋ ํฐ๋ฆฌ์์ test_* ๋๋ *_test๋ผ๋ ์ด๋ฆ์ ๋ชจ๋ ์ฐพ๊ธฐ
2. ํด๋น ๋ชจ๋์์ unittest.TestCase๋ฅผ ์์ํ ํด๋์ค๋ฅผ ์ฐพ๊ธฐ
3. ํด๋น ํด๋์ค์์ test_๋ก ์์ํ๋ ๋ฉ์๋๋ฅผ ์ฐพ๊ธฐ
ํ ์คํธ๋ฅผ ์ํด์ ์ ์์๊ฑฐ๋ ์์คํ ์ ์ํ ํด๋์ค๋ฅผ ๋ง๋ค์ด๋ด ๋๋ค.
# pruduct.py
class Product:
def __init__(self, name, size, color): # Product ์ธ์คํด์ค๊ฐ ์์ฑ๋ ๋ ์ํ ์์ฑ์ด ์ง์
self.name = name
self.size = size
self.color = color
def transform_name_for_sku(self):
return self.name.upper()
def transform_color_for_sku(self):
return self.color.upper()
def generate_sku(self): # SKU๋ ์ํ ์์ฑ์ ๊ณ ์ ํ๊ฒ ์๋ณํฉ๋๋ค.
"""
Generates a SKU for this product.
Example:
>>> small_black_shoes = Product('shoes', 'S', 'black')
>>> small_black_shoes.generate_sku()
'SHOES-S-BLACK'
"""
name = self.transform_name_for_sku()
color = self.transform_color_for_sku()
return f'{name}-{self.size}-{color}'
์ด ํด๋์ค๋ ์ ์์๊ฑฐ๋ ์์คํ ์์ ๊ตฌ๋งคํ ์ํ์ ๋ํ๋ ๋๋ค. ์ํ์ ์ด๋ฆ, ์ฌ์ด์ฆ ์ต์ , ์์ ์์ฑ์ ๊ฐ์ง๊ณ ์๊ณ ์ด๋ฌํ ์์ฑ์ ์กฐํฉ์ด ์ฌ๊ณ ๊ด๋ฆฌ๋จ์(Stock Keeping Unit, SKU)๋ฅผ ์์ฑํฉ๋๋ค. SKU๋ ๊ฐ๊ฒฉ๊ณผ ์ฌ๊ณ ๊ด๋ฆฌ๋ฅผ ์ํด ์ฌ์ฉ๋๋ ๊ณ ์ ํ ์๋ณ์์ ๋๋ค.
๊ธฐ๋ฅ ํ ์คํธ์ ๊ตฌ์กฐ๋ ์๋์ ๊ฐ์ด ์ด๋ฃจ์ด์ ธ ์์ต๋๋ค.
์ ๋ ฅ ์ค๋น -> ์์ ๊ฒฐ๊ณผ ์๋ณ -> ์ค์ ๊ฒฐ๊ณผ ์ป๊ธฐ -> ์์ ๊ฒฐ๊ณผ์ ์ค์ ๊ฒฐ๊ณผ ๋น๊ต
`Pruduct` ํด๋์ค์ `transform_name_for_sku`๋ฅผ ํ ์คํธ ํ๊ณ ์ถ๋ค๋ฉด ์๋์ ๊ณผ์ ์ผ๋ก ํ ์คํธ๋ฅผ ์งํํ๋ฉด ๋ฉ๋๋ค.
1. ์ด๋ฆ, ์ฌ์ด์ฆ, ์์์ผ๋ก Product ์ธ์คํด์ค ์์ฑ
2. `transform_name_for_sku`๊ฐ `name.upper()`๋ฅผ ๋ฐํํ๋์ง๋ฅผ ํ์ธ. ์์ ๊ฒฐ๊ณผ๋ ๋๋ฌธ์ ์ด๋ฆ
3. `Product` ์ธ์คํด์ค์ `transform_name_for_sku` ๋ฉ์๋๋ฅผ ํธ์ถํ๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ณ์์ ์ ์ฅ
4. ์์ ๊ฒฐ๊ณผ์ ์ค์ ๊ฒฐ๊ณผ๋ฅผ ๋น๊ต
์ฒซ ๋ฒ์งธ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํด๋ด ๋๋ค.
# test_product.py
import unittest
from product import Product
class ProductTestCase(unittest.TestCase):
def test_transform_name_for_sku(self):
# ์ด ์์ฑ์ ๊ฐ์ง ์ํ์ ๋ง๋ค์ด์ transform_name_for_sku ๋ฅผ ํ
์คํธํ๊ธฐ ์ํ ์ค๋น๋ฅผ ํฉ๋๋ค.
small_black_shoes = Product('shoes', 'S', 'black')
# ์์๋๋ ๊ฐ์
๋๋ค.
expected_value = 'SHOES'
# ๋น๊ต๋ฅผ ์ํด ์ค์ ๊ฐ์ ์ป์ต๋๋ค.
actual_value = small_black_shoes.transform_name_for_sku()
# ๋ ๊ฐ์ ๋น๊ตํฉ๋๋ค(๊ฐ๋ค๊ณ ๊ฐ์ ํ๊ธฐ ๋๋ฌธ์ assertEqual๋ฅผ ์ฌ์ฉํฉ๋๋ค.)
self.assertEqual(expected_value, actual_value)
์ด๋ ๊ฒ ์์ฑํ ํ์ unittest๋ฅผ ์คํํฉ๋๋ค.
> python -m unittest
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
์ ์์ ์ผ๋ก ํ ์คํธ๋ฅผ ํต๊ณผํ์ฌ OK๊ฐ ํ์๋ฉ๋๋ค. ์์ expected_value๋ฅผ 'SHOEZ'๋ก ๋ณ๊ฒฝํ๊ณ ๋ค์ ์ฝ๋๋ฅผ ์คํํด๋ด ๋๋ค.
> python -m unittest
F
======================================================================
FAIL: test_transform_name_for_sku (test_product.ProductTestCase.test_transform_name_for_sku)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_product.py", line 10, in test_transform_name_for_sku
self.assertEqual(expected_value, actual_value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 'SHOEZ' != 'SHOES'
- SHOEZ
? ^
+ SHOES
? ^
----------------------------------------------------------------------
Ran 1 test in 0.002s
์์๋๋ ๊ฒฐ๊ณผ์ ๋ค๋ฅธ ๊ฐ์ด ๋์ฌ๋๋ ํ ์คํธ์ ์คํจํ์๋ค๋ ์๋ฆผ์ด ํ์๋ฉ๋๋ค.
ํตํฉ ํ ์คํธ(integration testing)
ํตํฉํ ์คํธ๋ ์ผ๋ จ์ ๋จ์ ์์ ์ ์ฒด๊ฐ ์ ๋์ํ๋์ง์ ์ด์ ์ ๋ก๋๋ค. ๋ง์ฝ 10๊ฐ์ ์๋ฒฝํ ๋จ์๊ธฐ๋ฅ์ด ์๋ค๊ณ ํ๋๋ผ๋ ์ด๊ฒ๋ค์ ๊ฒฐํฉํ์ฌ ์ํ๋ ์์ ์ ํ ์ ์๋ค๋ฉด ์ฌ๋ฐ๋ฅธ ๊ธฐ๋ฅ์ ํ ์ ์์ต๋๋ค. ํตํฉ ํ ์คํธ์ ๊ฑธ๋ฆฌ๋ ์๊ฐ์ ์ผ๋ฐ์ ์ผ๋ก ๋จ์ ํ ์คํธ๋ณด๋ค ์ค๋ ๊ฑธ๋ฆฝ๋๋ค.
ํตํฉ ํ ์คํธ ์ผ์ด์ค๋ฅผ ์์ฑํ๊ธฐ ์ํด `shoppingCart` ํด๋์ค๋ฅผ ๋ง๋ค์ด์ ์ํ์ ์ถ๊ฐ ๋๋ ์ญ์ ํ ์ ์๊ฒ ํฉ๋๋ค. ์ฅ๋ฐ๊ตฌ๋ ๋ฐ์ดํฐ๋ ์๋์ ๊ฐ์ด ๋์ ๋๋ฆฌ ํํ๋ก ์ฌ์ฉํฉ๋๋ค.
{
'SHOES-S-BLUE': {'quantity': 1},
'SHIRT-M-GRAY': {'quantity': 1}
}
`shoppingCart` ํด๋์ค๋ ์์ ๋์ ๋๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ๋ ๋ฐฉ์์ผ๋ก ์ํ์ ์ถ๊ฐํ๊ฑฐ๋ ์ ๊ฑฐํ ์ ์๋ ๋ฉ์๋๊ฐ ์์ต๋๋ค.
# cart.py
from collections import defaultdict
class ShoppingCart:
def __init__(self):
self.products = defaultdict(lambda: defaultdict(int)) # defaultdict๋ฅผ ์ฌ์ฉํ๋ฉด ๋์
๋๋ฆฌ์ ์ ํ์ด ์ด๋ฏธ ์๋์ง ๊ฒ์ฌํ๋ ๋ก์ง์ด ๋จ์ํด์ง๋๋ค.
def add_product(self, product, quantity=1): # ์ํ ์๋ ์ถ๊ฐํ๊ธฐ
self.products[product.generate_sku()]['quantity'] += quantity
def remove_product(self, product, quantity=1): # ์ฅ๋ฐ๊ตฌ๋์์ ์ํ ์ ๊ฑฐํ๊ธฐ
sku = product.generate_sku()
self.products[sku]['quantity'] -= quantity
if self.products[sku]['quantity'] <= 0:
del self.products[sku]
๋ค์๊ณผ ๊ฐ์ ๊ณผ์ ์ผ๋ก ํตํฉ ํ ์คํธ๋ฅผ ์งํํฉ๋๋ค.
- ์ฅ๋ฐ๊ตฌ๋๋ Product ์ธ์คํด์ค์ generate_sku ๋ฉ์๋๋ฅผ ์ฌ์ฉํฉ๋๋ค.
- ์ํ์ ์ถ๊ฐํ๊ณ ์ ๊ฑฐํ๋ ์์ ์ ์์ฐจ์ ์ผ๋ก ์คํ๋์ด์ผ ํ๋ฉฐ, ์ด์ ์ ์ถ๊ฐ๋ ์ ํ๋ ์ ๊ฑฐํ ์ ์์ด์ผ ํฉ๋๋ค.
# test_cart.py
import unittest
from cart import ShoppingCart
from product import Product
class ShoppingCartTestCase(unittest.TestCase):
def test_cart_initially_empty(self):
cart = ShoppingCart()
# ์นดํธ๊ฐ ๋น์ด์๋์ง ํ
์คํธํฉ๋๋ค.
self.assertDictEqual({}, cart.products)
def test_add_two_of_a_product(self):
cart = ShoppingCart()
product = Product('shoes', 'S', 'blue')
# ์นดํธ์ ์ํ์ ์ถ๊ฐํฉ๋๋ค.
cart.add_product(product, quantity=2)
# ์ถ๊ฐ๋ ์ํ์ด ๋์ผํ์ง ํ์ธํฉ๋๋ค.
self.assertDictEqual({'SHOES-S-BLUE': {'quantity': 2}}, cart.products)
def test_add_two_different_products(self):
cart = ShoppingCart()
product_one = Product('shoes', 'S', 'blue')
product_two = Product('shirt', 'M', 'gray')
# ๋ ๊ฐ์ ์ํ์ ์ถ๊ฐํฉ๋๋ค.
cart.add_product(product_one)
cart.add_product(product_two)
# ์์๋๋ ๊ฒฐ๊ณผ์ ๋น๊ตํฉ๋๋ค.
self.assertDictEqual(
{
'SHOES-S-BLUE': {'quantity': 1},
'SHIRT-M-GRAY': {'quantity': 1}
},
cart.products
)
def test_add_and_remove_product(self):
cart = ShoppingCart()
product = Product('shoes', 'S', 'blue')
# ์ํ์ ์ถ๊ฐํ๊ณ ์ ๊ฑฐํฉ๋๋ค.
cart.add_product(product)
cart.remove_product(product)
# ์นดํธ์ ์ ํ์ด ๋น์ด์๋์ง ํ์ธํฉ๋๋ค.
self.assertDictEqual({}, cart.products)
def test_remove_too_many_products(self):
cart = ShoppingCart()
product = Product('shoes', 'S', 'blue')
cart.add_product(product)
cart.remove_product(product, quantity=2)
# ์นดํธ์ ์ ํ์ด ๋น์๋์ง ํ์ธํฉ๋๋ค.
self.assertDictEqual({}, cart.products)
ํ์ด์ฌ์ ๋ด์ฅ๋ unittest๋ ํ๋ฅญํ์ง๋ง ์กฐ๊ธ ๋ ๊ฐ๊ฒฐํ ๋ฐฉ์์ผ๋ก ํ ์คํธ๋ฅผ ํ๊ณ ์ถ๋ค๋ฉด pytest๋ฅผ ์ด์ฉํ ์ ์์ต๋๋ค.
pytest๋ฅผ ์ค์นํ๋ฉด ๊ฐ๋จํ๊ฒ pytest๋ง ์ ๋ ฅํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ์ ๊ณตํด์ค๋๋ค.
> pytest
==================== test session starts ====================
platform win32 -- Python 3.9.12, pytest-7.1.1, pluggy-1.3.0
rootdir: [ํ
์คํธ ์คํํ ์ ๋ ๊ฒฝ๋ก]
plugins: anyio-3.5.0
collected 3 items
test_product.py ... [100%]
===================== 3 passed in 0.03s =====================
unittest๋ฅผ pytest๋ก ์ ํํ๊ธฐ ์ํด์๋
- unittest import ๊ตฌ๋ฌธ์ ์ ๊ฑฐํ๊ณ unittest.TestCase์ ์์์ ์ ๊ฑฐํฉ๋๋ค.
- ๋ชจ๋ self.assertEquel(expect, actual)์ assert actual == expect๋ก ๋ณ๊ฒฝํฉ๋๋ค.
from product import Product
class TestProduct: # ๊ธฐ๋ณธ ํด๋์ค๋ฅผ ์์ํ์ง ์์๋ ๋ฉ๋๋ค.
def test_transform_name_for_sku(self):
small_black_shoes = Product('shoes', 'S', 'black')
assert small_black_shoes.transform_name_for_sku() == 'SHOES' # assert๋ฅผ ์ฌ์ฉํ์ฌ ๋น๊ตํ ์ ์์ต๋๋ค.
def test_transform_color_for_sku(self):
small_black_shoes = Product('shoes', 'S', 'black')
assert small_black_shoes.transform_color_for_sku() == 'BLACK'
def test_generate_sku(self):
small_black_shoes = Product('shoes', 'S', 'black')
assert small_black_shoes.generate_sku() == 'SHOES-S-BLACK'
์์ ๊ฐ์ด ๋ ์ฝ๊ธฐ ์ฌ์ด ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
์ด๋ฒ ๊ฒ์๊ธ์์๋ ๊ฐ๋จํ ์ฝ๋๋ฅผ ํตํด ํ ์คํธ๋ฅผ ์ํํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์์๋ณด์์ต๋๋ค. ์ค๋ ๊ฒ์๊ธ์ ๋ด์ฉ์ ์์ฝํด๋ณด๋ฉด ์๋์ ๊ฐ์ต๋๋ค.
- ๊ธฐ๋ฅ ํ ์คํธ๋ ์ฃผ์ด์ง ์ ๋ ฅ์ ๋ํด ์์ํ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋ ์ง ํ์ธํฉ๋๋ค.
- ํ ์คํธ๋ ๋ฒ๊ทธ๋ฅผ ์ก์์ฃผ๊ณ ๋ฆฌํฉํ ๋ง ์ฝ๋๋ฅผ ๋ ์ฝ๊ฒ ๋ง๋ค์ด์ฃผ์ด ์ฅ๊ธฐ์ ์ผ๋ก ์๊ฐ์ ์ ์ฝํ๋ ํจ๊ณผ๋ฅผ ๋ ๋๋ค.
- unittest์ pytest๋ ํ์ด์ฌ์์ ๋๋ฆฌ ์ฌ์ฉ๋๋ ๋จ์/ํตํฉ ํ ์คํธ ํ๋ ์์ํฌ์ ๋๋ค.
reference
๋ฐ์ธ ํ๋ผ๋, ํ๋ก๊ทธ๋๋จธ๋ฅผ ์ํ ํ์ด์ฌ
'note' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[hadoop] yarn demon ์คํ์ java.lang.NoClassDefFoundError: org/apache/hadoop/yarn/s (0) | 2024.02.12 |
---|---|
[Spark] Cluster Sizing - ์คํํฌ ํด๋ฌ์คํฐ ์ฌ์ด์ฆ ์ ํ๊ธฐ (0) | 2024.02.10 |
๋คํธ์ํน์ ํตํด ๋ฐฐ์ด ๊ฒ๋ค (0) | 2023.12.31 |
airflow ์ฌ์ฉ๊ธฐ (0) | 2023.12.05 |
[airflow] ubuntu ์๋ฒ์ airflow ์๋น์ค ๋ฑ๋กํ๊ธฐ (0) | 2023.11.18 |