MariaDB 10.1.2 하위 버전의 소숫점이 포함된 datetime 형식에 주의하자
MariaDB 10.1.2 하위 버전에서는 소숫점을 가진 datetime 값을 저장할 때 독특한 형식을 사용한다. 이 독특한 형식이 데이터의 저장이나 조회 등의 일반적인 작업에서는 문제점으로 드러나지 않는다. 하지만 binlog를 사용해야 하는 일부 작업에서는 문제가 발생할 수 있...
python 에는 널리 알려져 사용되는 여러 도구들이 이미 많습니다. 특히 pytest 는 좀 더 직관적인 assert 구문과 test 결과를 제공하며, 많은 plugin 을 보유하고 있습니다. 하지만 여러 도구들을 알아보기 전에 python testing에 기반이 되는 unittest 프레임워크의 개념과 사용법에 대해 알아보겠습니다.
오늘은 그 중 fixture의 종류와 사용범위에 대해 알아보겠습니다.
테스트 픽스쳐는 테스트를 수행 시 필요한 리소스 준비과 이를 정리하는 동작에 해당합니다. unittest 프레임워크에서는 fixture를 여러 scope에서 사용할 수 있도록 기능을 제공합니다. 아래에서 Test, Class, Module Scope를 위한 fixture 사용법에 대해 알아보겠습니다.
TestCase 의 각 테스트에서 사용될 fixture의 준비와 정리는 setUp()과 tearDown()을 사용하게 됩니다. 테스트마다 반복될 수 있는 fixture를 setUp() 메소드와 tearDown() 메소드를 사용해 분리할 수 있습니다. 테스트 프레임워크가 각 테스트 실행 전후에 두 메소드를 자동으로 호출합니다.
import unittest
class RemainderTest(unittest.TestCase):
def setUp(self) -> None:
self.number = 2
print('setUp')
def tearDown(self) -> None:
print('tearDown')
def test_even(self):
self.assertEqual(self.number % 2, 0)
def test_odd(self):
self.assertNotEqual(self.number % 2, 1)
위 테스트를 실행한 결과를 통해 각 테스트별로 매번 fixture가 생성되는 것을 알 수 있습니다.
setUp
tearDown
setUp
tearDown
setUp() 메소드 작업에서 예외가 발생하면 tearDown 메소드는 호출되지 않습니다.
class RemainderTest(unittest.TestCase):
def setUp(self) -> None:
self.number = 2
print('setUp')
raise Exception()
def tearDown(self) -> None:
print('tearDown')
def test_even(self):
self.assertEqual(self.number % 2, 0)
def test_odd(self):
self.assertNotEqual(self.number % 2, 1)
setUp
Error
Traceback (most recent call last):
...
setUp
Error
Traceback (most recent call last):
...
setUp 메소드 실행이 성공했다면 테스트 실패 여부과 관계없이 tearDown 메소드가 호출됩니다.
테스트 중에 사용된 자원을 정리하기 위해 tearDown 이후에 불리는 함수를 추가할 수 있습니다. 추가된 순서의 반대 순서(LIFO)로 불리게 됩니다. 함수가 추가될 때 addCleanup에 같이 전달된 위치 인자나 키워드 인자와 함께 호출됩니다.
def cleanUp():
print('cleanUp')
class RemainderTest(unittest.TestCase):
def setUp(self) -> None:
self.number = 2
print('setUp')
self.addCleanup(cleanUp)
def tearDown(self) -> None:
print('tearDown')
def test_even(self):
self.assertEqual(self.number % 2, 0)
setUp
tearDown
cleanUp
또한 setUp 메소드에서 예외가 발생하면 tearDown 메소드가 호출되지 않아도 doCleanups 메소드가 실행됩니다.
def cleanUp():
print('cleanUp')
class RemainderTest(unittest.TestCase):
def setUp(self) -> None:
self.number = 2
print('setUp')
self.addCleanup(cleanUp)
raise Exception()
def tearDown(self) -> None:
print('tearDown')
def test_even(self):
self.assertEqual(self.number % 2, 0)
setUp
cleanUp
Error
Traceback (most recent call last):
doCleanUp 메소드를 직접 호출하여 addCleanUp에 추가된 함수들을 tearDown 호출 이전에 정리할 수도 있습니다.
def cleanUp():
print('cleanUp')
class RemainderTest(unittest.TestCase):
def setUp(self) -> None:
self.number = 2
print('setUp')
self.addCleanup(cleanUp)
def tearDown(self) -> None:
print('tearDown')
def test_even(self):
self.assertEqual(self.number % 2, 0)
self.doCleanups()
setUp
cleanUp
tearDown
Test Class 범위에 fixture는 unittest.TestSuite에 의해 관리되는 setUpClass와 tearDownClass가 있습니다. 해당 fixture는 Test Class의 모든 테스트와 공유되는 점을 주의해야 합니다. 아래와 같이 특정 테스트에서 str_list fixture의 수정이 일어나게 되면 이후 테스트에 영향을 미치게 됩니다.
class JoinTest(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
cls.str_list = ['foo', 'bar']
print('setUpClass')
@classmethod
def tearDownClass(cls) -> None:
print('tearDownClass')
def test_join_with_colon(self):
expected = 'foo:bar'
self.assertEqual(':'.join(self.str_list), expected)
self.str_list.append('baz')
def test_join_with_comma(self):
expected = 'foo,bar'
self.assertEqual(','.join(self.str_list), expected)
self.str_list.append('baz')
setUpClass 메소드 작업에서 예외가 발생하면 tearDownClass 메소드는 호출되지 않습니다.
test scope와 마찬가지로 cleanUp을 위한 addClassCleanup 메소드를 제공합니다. setUpClass 메소드에서 예외가 발생하면 tearDownClass 메소드가 호출되지 않아도 doClassCleanups 메소드가 실행됩니다.
def classCleanUp():
print('classCleanUp')
class JoinTest(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
cls.str_list = ['foo', 'bar']
print('setUpClass')
cls.addClassCleanup(classCleanUp)
@classmethod
def tearDownClass(cls) -> None:
print('tearDownClass')
def test_join_with_colon(self):
expected = 'foo:bar'
self.assertEqual(':'.join(self.str_list), expected)
addClassCleanup에 추가된 함수들을 tearDownClass 이전에 정리하고 싶다면 doClassCleanups 메소드를 사용해 미리 정리할 수 있습니다.
module scope 에서는 setUpModule과 tearDownModule을 제공하며 함수로 작성되어야 합니다. 마찬가지로 setUpModule 실행 중 예외가 발생하면 tearDownModule 함수는 호출되지 않습니다.
def setUpModule():
print('setUpModule')
def tearDownModule():
print('tearDownModule')
class JoinTest(unittest.TestCase):
def test_join_with_colon(self):
expected = 'foo:bar'
self.assertEqual(':'.join(['foo', 'bar']), expected)
class RemainderTest(unittest.TestCase):
def test_even(self):
self.assertEqual(2 % 2, 0)
setUpModule
tearDownModule
module scope에 cleanUp을 위해 unittest.addModuleCleanup 함수를 제공합니다. tearDownModule 함수가 호출된 이후 unittest.case.doModuleCleanups 함수를 통해 추가된 cleanUp 함수들이 호출됩니다.
def setUpModule():
print('setUpModule')
def tearDownModule():
print('tearDownModule')
def moduleCleanUp():
print('moduleCleanUp')
class JoinTest(unittest.TestCase):
def test_join_with_colon(self):
expected = 'foo:bar'
self.assertEqual(':'.join(['foo', 'bar']), expected)
unittest.addModuleCleanup(moduleCleanUp)
setUpModule
tearDownModule
moduleCleanUp
tearDownModule이 호출되기 전에 추가된 정리 함수들을 호출하고 싶다면 unittest.case.doModuleCleanups 함수를 직접 호출합니다.
def setUpModule():
print('setUpModule')
def tearDownModule():
print('tearDownModule')
def moduleCleanUp():
print('moduleCleanUp')
unittest.addModuleCleanup(moduleCleanUp)
class JoinTest(unittest.TestCase):
def test_join_with_colon(self):
expected = 'foo:bar'
self.assertEqual(':'.join(['foo', 'bar']), expected)
unittest.case.doModuleCleanups()
class RemainderTest(unittest.TestCase):
def test_even(self):
self.assertEqual(2 % 2, 0)
setUpModule
moduleCleanUp
tearDownModule
def setUpModule():
print('setUpModule')
def tearDownModule():
print('tearDownModule')
def cleanUp():
print('cleanUp')
def classCleanUp():
print('classCleanUp')
def moduleCleanUp():
print('moduleCleanUp')
unittest.addModuleCleanup(moduleCleanUp)
class JoinTest(unittest.TestCase):
def setUp(self) -> None:
print('setUp')
self.addCleanup(cleanUp)
def tearDown(self) -> None:
print('tearDown')
@classmethod
def setUpClass(cls) -> None:
print('setUpClass')
cls.addClassCleanup(classCleanUp)
@classmethod
def tearDownClass(cls) -> None:
print('tearDownClass')
def test_join_with_colon(self):
expected = 'foo:bar'
self.assertEqual(':'.join(['foo', 'bar']), expected)
위에서 언급된 fixture scope 를 모두 포함한 결과를 보면 호출 순서는 아래와 같습니다.
setUpModule
setUpClass
setUp
tearDown
cleanUp
tearDownClass
classCleanUp
tearDownModule
moduleCleanUp
python unittest를 사용해 테스트 작성 시 fixture 별 scope와 호출 시점과 조건을 잘 파악해야 합니다. 여러 scope의 fixture를 잘 활용하면 중복을 해결하고 테스트 성능에 도움이 되지만 잘못 사용할 경우 의도와 다른 테스트 결과가 출력될 수 있음에 주의하며 사용하는 것이 좋습니다.
MariaDB 10.1.2 하위 버전에서는 소숫점을 가진 datetime 값을 저장할 때 독특한 형식을 사용한다. 이 독특한 형식이 데이터의 저장이나 조회 등의 일반적인 작업에서는 문제점으로 드러나지 않는다. 하지만 binlog를 사용해야 하는 일부 작업에서는 문제가 발생할 수 있...
AWS managed 서비스는 각각의 로깅방식을 제공하고 대부분 Cloudwatch logs를 통해 지원한다. API Gateway도 마찬가지로 AWS 콘솔 설정을 통해 실행 로그와 액세스 로그를 기록할 수 있다. 다만 로그 보관주기를 Gateway 콘솔에서 설정할 수 없다는 단점...
ubuntu 서버에서 apt install 사용 시 apt lock 이 발생하며 설치가 실패하는 경우가 간헐적으로 발생합니다. 저의 경우 ubuntu 이미지를 기반으로 진행되는 초반 provisiong 시점에 자주 발생했습니다. [stdout]Waiting for cache loc...
AWS 상에서 다양한 아키텍처를 구성하다보면 서비스의 상태를 모니터링하거나 이벤트 알림을 원하는 채널에서 받을 필요가 있습니다. 원하는 서비스의 콘솔을 통해 제공하는 경우도 있으나 디테일한 설정은 어렵거나 제공되지 않는 경우가 많습니다.
django logging django는 python의 builtin 로깅 모듈을 사용하여 시스템 로깅 작업을 수행합니다. settings.py LOGGING을 통해 설정이 가능합니다. setting.py 에 LOGGING 설정이 없을 경우 아래 예시처럼 default 설정을 제공...
Tomcat 의 ConnectionPool Tomcat 은 효율적인 Connection Pool 관리를 위해 Commons DBCP 보다 개선된 Tomcat DBCP 를 사용합니다. Idle Connection 수를 조정하고 Active 상태가 오래 지속중인 Connection 을...
python testing tool python 에는 널리 알려져 사용되는 여러 도구들이 이미 많습니다. 특히 pytest 는 좀 더 직관적인 assert 구문과 test 결과를 제공하며, 많은 plugin 을 보유하고 있습니다. 하지만 여러 도구들을 알아보기 전에 python t...