python unittest

Post on 19-Jul-2015

399 Views

Category:

Software

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Python UnitTest

무엇을 테스트 해야 하지? == 무엇을 만들어야 하는지 모름

Test passes테스트를 통과 할 수 있게 최소

한의 프로그래밍

실패하는 테스트를 작성

Test fails Refactor코드 의존성 제거 및 품질 향상

Basic Exampleimport randomimport unittestclass PizzaTest(unittest.TestCase): def setUp(self): self.seq = list(range(10)) def test_shuffle(self): random.shuffle(self.seq) self.seq.sort() self.assertEqual(self.seq, list(range(10))) #리스트를 변경해야하는데 튜플은 변경이 안되어 TypeError 발생 self.assertRaises(TypeError, random.shuffle, (1,2,3)) def test_choice(self): element = random.choice(self.seq) self.assertTrue(element in self.seq) def test_sample(self): with self.assertRaises(ValueError): #첫번째 파라미터가 가진 리스트 갯수 보다 많은 수를 입력하여 ValueError가 발생함 random.sample(self.seq, 20) for element in random.sample(self.seq, 5): self.assertTrue(element in self.seq)

테스트 함수 실행 될때마다 먼저 실행되는 준비 함수

unittest.TestCase를 상속받아야 함

테스트 할 함수의 이름이test로 시작해야 함

$ python3 -m unittest tests.py

Test Discovery

python -m unittest discover -s project_directory -p '*_test.py'

테스트를 찾는 패턴을 커스터마이징 할 수 있다.

-v, --verboseVerbose output

-s, --start-directory directoryDirectory to start discovery (. default)

-p, --pattern patternPattern to match test files (test*.py default)

-t, --top-level-directory directory

Test Suite

내가 원하는 대로 테스트 구성 하기

def suite(): suite = unittest.TestSuite() suite.addTest(PizzaTest('test_choice')) # suite.addTest(PizzaTest('test_sample')) return suiteif __name__ == '__main__': unittest.TextTestRunner().run(suite())

Test Skip

@unittest.skip("demonstrating skipping") def test_nothing(self): self.fail("shouldn't happen") @unittest.skipIf(mylib.__version__ < (1, 3), "not supported in this library version") def test_format(self): # Tests that work for only a certain version of the library. pass@unittest.skipUnless(sys.platform.startswith("win"), "requires Windows") def test_windows_support(self): # windows specific testing code pass

Python3.4 Assertions

assertEqual(a, b)

a와 b가 같으면 테스트 성공 그렇지 않으면 실패

assertNotEqual(a, b)

a와 b가 같지 않으면 테스트 성공

assertTrue(x), assertFalse(x)

함수 의미와 동일하게 True이거나 False이면 성공

assertIs(a, b), assertIsNot(a, b)

a와 b가 같은 오브젝트 이면 성공하거나 아니면 성공

assertIsNone(x), assertIsNotNone(x)

x가 None 이면 성공이거나 None이 아니면 성공

assertIn(a, b), assertNotIn(a, b)

a가 b에 속해 있으면 성공, a가 b에 속하지 성공

assertIsInstance(a, b), assertNotIsInstance(a, b)

a = objectb= class

a가 b의 인스턴스이면 성공, 아니면 성공

assertRaises(exc, fun, *args, **kwds)

def order(): raise Exception

다양한 Exception을 테스트 할 수 있다

def test_order(self): with self.assertRaises(Exception): order()

assertRaisesRegex(exc, r, fun, *args, **kwds)

Exception 메세지에 정규식이 매치가 되면 성공

def test_exception_message_regex(self): self.assertRaisesRegex(ValueError, "invalid literal for.*XYZ'$", int, 'XYZ')

더 있지만 생략

https://docs.python.org/3.4/library/unittest.html#unittest.TestCase.assertAlmostEqual

Django에는 assertion이 더 있음

https://docs.djangoproject.com/en/dev/topics/testing/tools/#assertions

Mock실제 어플리케이션 객체를 특정한 방식으로 흉내 내는 객체

3을 리턴하는 모의 객체 만들어 보기

from unittest.mock import MagicMockclass A(object): def test(self): passclass AuthTest(TestCase): def setUp(self): pass def test_mock(self): inst = A() inst.method = MagicMock(return_value=3) self.assertEqual(inst.method(1), 3) inst.method.assert_called_with(1)

3을 리턴하도록 목 객체 생성

정말 3을 리턴하는지테스트

mock 객체가 호출 되었는지 확인

Raising an exception when a mock is called

def test_side_effect(self): mock = Mock(side_effect=KeyError('Foo')) self.assertRaises(KeyError, mock)

patch

mock.patch를 사용하면 외부 라이브러리의 행위를 바꿀 수 있다.

Fake clientfrom django.test import Clientfrom unittest.mock import MagicMock, Mock, patchdef get_fake_request(status_code, content): m = Mock() m.status_code = status_code m.content = content def fake_get(url, *args, **kwargs): return m return fake_getclass MockTest(TestCase): @patch('django.test.Client.get', get_fake_request(200, 'Fake')) def test_request(self): res = Client.get('http://fake.com') self.assertEqual(res.status_code, 200)

Django UnitTest

Request test

def test_test_view(self): c = Client() res = c.get('/test_view/', {}) e = {'result': 1} self.assertJSONEqual(res.content.decode('utf-8'), json.dumps(e))

post, head, put, patch, delete, trace

login_required view 라면?

@login_requireddef auth_view(request): return HttpResponse(status=200)

def test_login_required_view(self): client = Client() res = client.login(username='debug', password='debug') res = client.get('/auth_view/') self.assertEqual(res.status_code, 200)

Client.login 을 호출하여 로그인을 하면 됨

Rainist, For Making Better Decision

http://www.rainist.com

최명규

top related