class TopHeroesHandlerTestCase(unittest.TestCase): """Top Heroes handler""" def setUp(self): """SetUp é chamado no inicio de cada teste""" self.mock_db = MockFirestore() self.patcher = patch('modules.main.MainModule.get_firestore_db', return_value=self.mock_db) self.patcher.start() # Nessa linha vamos iniciar a API nos testes self.app = app.test_client() def tearDown(self): """O tearDown é chamado no final de cada teste""" self.patcher.stop() self.mock_db.reset() @staticmethod def create_hero(hero_name, universe): """Create a hero for tests""" hero = Hero() hero.name = hero_name hero.description = '{0} description'.format(hero_name) hero.universe = universe hero.save() return hero def test_get_top_heroes(self): """Test get top heroes""" # Aqui vamos fazer um loop e criar 20 herois # E o nome vai ser hero + index do loop, ex: "Hero 1" for index in range(1, 21): self.create_hero('Hero {0}'.format(index), 'marvel') # Fazendo a primeira consulta a url e conferindo a resposta response = self.app.get(path='/top-heroes') first_hero_list = response.get_json()['heroes'] self.assertEqual(len(first_hero_list), 4) self.assertEqual(response.status_code, 200) # Fazendo a segunda consulta a url e conferindo a resposta response = self.app.get(path='/top-heroes') self.assertEqual(response.status_code, 200) second_hero_list = response.get_json()['heroes'] self.assertEqual(len(second_hero_list), 4) # Comparando as duas listas para ver se são diferentes # Pois essa url precisa sempre retornar herois diferentes self.assertNotEqual(first_hero_list, second_hero_list)
class HeroesSearchHandlerTestCase(unittest.TestCase): """Heroes search handler""" def setUp(self): """SetUp é chamado no inicio de cada teste""" self.mock_db = MockFirestore() self.patcher = patch( 'modules.main.MainModule.get_firestore_db', return_value=self.mock_db) self.patcher.start() self.app = app.test_client() def tearDown(self): """O tearDown é chamado no final de cada teste""" self.patcher.stop() self.mock_db.reset() def test_search_hero(self): """Test search hero by name""" # Criando dois herois com nomes diferentes self.create_hero('Superman', 'dc') self.create_hero('Batman', 'dc') # Pesquisando o heroi Superman response = self.app.get(path='/search?name=' + 'Superman') # Conferindo o status da requisição self.assertEqual(response.status_code, 200) # Conferindo se voltou somente um heroi self.assertEqual(len(response.get_json()), 1) # Conferindo o nome do heroi que voltou self.assertEqual(response.get_json()[0]['name'], 'Superman') def test_search_hero_with_lowercase_param_name(self): """Test search hero by lowercase param name""" # Criando dois herois com nomes diferentes self.create_hero('Superman', 'dc') self.create_hero('Batman', 'dc') # Pesquisando o heroi Superman com a primeira letra minuscula # No metodo view vocês só precisam chamar o metodo title para deixar # a primeira letra maiuscula e o teste ira passar response = self.app.get(path='/search?name=' + 'superman') # Conferindo o status da requisição self.assertEqual(response.status_code, 200) # Conferindo se voltou somente um heroi self.assertEqual(len(response.get_json()), 1) # Conferindo o nome do heroi que voltou self.assertEqual(response.get_json()[0]['name'], 'Superman') def test_search_hero_max_returned_items(self): """Test search hero max items returned in query""" # Criando 15 herois com o mesmo nome para testar o limite da consulta for _ in range(15): self.create_hero('Superman', 'dc') # Pesquisando o heroi response = self.app.get(path='/search?name=' + 'Superman') # Conferindo o status da requisição self.assertEqual(response.status_code, 200) # Conferindo se voltou somente 10 herois que é o limite mencionado self.assertEqual(len(response.get_json()), 10) def test_search_hero_without_param_name(self): """Test search hero without param name""" # Pesquisando o heroi sem o parametro name, fazendo isso a requisição # deve retornar o status 400(Bad request) e retornar um json com # a mensagem de erro response = self.app.get(path='/search?name=') # Conferindo o status da requisição self.assertEqual(response.status_code, 400) # Conferindo a mensagem de erro que voltou self.assertDictEqual( response.get_json(), {'message': 'Bad request, param name is required'} ) @staticmethod def create_hero(hero_name, universe): hero = Hero() hero.name = hero_name hero.description = '{0} description'.format(hero_name) hero.universe = universe hero.save() return hero
class TestHeroModel(unittest.TestCase): """Test hero model""" def setUp(self): """SetUp é chamado no inicio de cada teste""" self.mock_db = MockFirestore() self.patcher = patch('modules.main.MainModule.get_firestore_db', return_value=self.mock_db) self.patcher.start() def tearDown(self): """O tearDown é chamado no final de cada teste""" self.patcher.stop() self.mock_db.reset() def test_save_and_get_hero(self): """Test save and get hero""" # Criando o novo heroi new_hero = Hero() new_hero.name = 'Superman' new_hero.description = 'Superman' new_hero.universe = 'dc' new_hero.save() # Obtendo o heroi pelo id hero = Hero.get_hero(new_hero.id) self.assertEqual(hero.name, 'Superman') self.assertEqual(hero.id, new_hero.id) def test_get_hero_not_found(self): """Test get hero not found""" hero = Hero.get_hero('ID_TEST') self.assertIsNone(hero) @staticmethod def create_hero(hero_name, universe): hero = Hero() hero.name = hero_name hero.description = '{0} description'.format(hero_name) hero.universe = universe hero.save() return hero def test_get_heroes(self): """Test get heroes""" # Aqui vamos fazer um loop e criar 20 herois for index in range(1, 21): self.create_hero('Hero {0}'.format(index), 'marvel') # Chamando o metodo para obter os herois heroes = Hero.get_heroes() # Percorrendo todos os herois e transformando eles em dict(json) heroes_dict = [hero.to_dict() for hero in heroes] # Consultando a quantidade de item que retornou self.assertEqual(len(heroes_dict), 16) for hero in heroes_dict: self.assertTrue(hero['name'].startswith('Hero')) def test_delete_hero(self): """Test delete hero""" # Criando o heroi hero = self.create_hero('Joker', 'dc') # excluindo o heroi Hero.delete(hero.id) # consultando se o heroi foi mesmo excluido self.assertIsNone(Hero.get_hero(hero.id))
class HeroesHandlerTestCase(unittest.TestCase): """Heroes handler""" def setUp(self): """SetUp é chamado no inicio de cada teste""" self.mock_db = MockFirestore() self.patcher = patch('modules.main.MainModule.get_firestore_db', return_value=self.mock_db) self.patcher.start() self.app = app.test_client() def tearDown(self): """O tearDown é chamado no final de cada teste""" self.patcher.stop() self.mock_db.reset() def test_create_a_new_hero(self): """This test should create a new hero""" hero_dict = { 'hero': { 'name': 'Superman', 'description': 'Superman description', 'universe': 'DC', 'imageUrl': 'https://super.abril.com.br/wp-content/uploads/2018/09/superman.png?w=1024' } } response = self.app.post(path='/heroes', json=hero_dict) # Conferindo se voltou 200 self.assertEqual(response.status_code, 200) # Conferindo a resposta da requisição self.assertIsNotNone(response.get_json()) self.assertIsNotNone(response.get_json()['id']) def test_get_heroes(self): """Test get this""" # Aqui vamos fazer um loop e criar 20 herois # E o nome vai ser hero + index do loop, ex: "Hero 1" for index in range(1, 21): self.create_hero('Hero {0}'.format(index), 'marvel') response = self.app.get(path='/heroes') # conferindo se voltou 200 # print(response) self.assertEqual(response.status_code, 200) # conferindo se a chave do cursor esta retornando um json self.assertIn('cursor', response.get_json()) # Conferindo a quantidade de herois que voltou no json self.assertEqual(len(response.get_json()['heroes']), 16) # Fazendo a segunda consulta enviando o cursor retornado cursor = response.get_json()['cursor'] response = self.app.get(path='/heroes?cursor=' + cursor) # Conferindo se voltou 200 self.assertEqual(response.status_code, 200) # Conferindo a quantidade de herois que voltou no json # Na primeira requisiçao voltou 16 herois entao precisa retornar mais 4 self.assertEqual(len(response.get_json()['heroes']), 4) @staticmethod def create_hero(hero_name, universe): hero = Hero() hero.name = hero_name hero.description = '{0} description'.format(hero_name) hero.universe = universe hero.save() return hero def test_get_hero(self): """Test get hero""" # Criando o heroi e salvando o id hero_id = self.create_hero('Hero', 'DC').id # Enviando a requisição para obter o heroi response = self.app.get('/hero/{0}'.format(hero_id)) self.assertEqual(response.status_code, 200) # Pegando o json da resposta hero_dict = response.get_json() self.assertEqual(hero_dict['name'], 'Hero') self.assertEqual(hero_dict['id'], hero_id) def test_get_hero_not_found(self): """Test get hero not found""" # Enviando a requisição para obter o heroi response = self.app.get('/hero/id_aleatorio') # A requisição vai voltar 404 pois não existe nenhum heroi com esse id self.assertEqual(response.status_code, 404) # Json retornado self.assertDictEqual(response.get_json(), {'message': 'Hero not found'}) def test_update_hero(self): """Test update hero""" # Criando o heroi com o nome hero hero = self.create_hero('Hero', 'DC') # Enviando a requisição para atualizar nome do heroi para "Hawkwoman" params = { 'hero': { 'name': 'Hawkwoman', 'description': hero.description, 'universe': hero.universe, 'imageUrl': 'https://gartic.com.br/imgs/mural/ti/tica_/pantera-negra.png' } } response = self.app.post(path='/hero/{0}'.format(hero.id), json=params) # Resposta da requisição self.assertEqual(response.status_code, 200) # Obtendo o heroi atualizado para conferir o novo nome hero_updated = Hero.get_hero(hero.id) self.assertEqual(hero_updated.name, 'Hawkwoman') def test_delete_hero(self): """Test delete hero""" # Criando o heroi hero = self.create_hero('Hero', 'DC') # Enviando a requisição para excluir o heroi response = self.app.delete(path='/hero/{0}'.format(hero.id)) # Resposta da requisição self.assertEqual(response.status_code, 200) # Conferindo a mensagem que voltou self.assertEqual(response.get_json(), {'message': 'Hero deleted'}) # Obtendo o heroi diretamente no banco de dados para conferir se foi # excluido mesmo self.assertIsNone(Hero.get_hero(hero.id)) def test_create_hero_without_name(self): """Test create hero without name""" params = { 'hero': { 'name': '', 'description': '', 'universe': 'DC', 'imageUrl': 'https://image.com.br/image.jpg' } } response = self.app.post(path='/heroes', json=params) self.assertEqual(response.status_code, 500) self.assertEqual(response.get_json()['details'], 'Bad request, name is required') def test_create_hero_with_name_formatted(self): """Test create hero with uppercase name and blank spaces""" params = { 'hero': { 'name': ' SUPERMAN ', 'description': 'Hero description', 'universe': 'DC', 'imageUrl': 'https://image.com.br/image.jpg' } } response = self.app.post(path='/heroes', json=params) self.assertEqual(response.status_code, 200) # Obtendo o heroi no banco de dados para conferir o nome hero_updated = Hero.get_hero(response.get_json()['id']) self.assertEqual(hero_updated.name, 'Superman') def test_create_hero_with_invalid_universe(self): """Test create hero with invalid universe""" params = { 'hero': { 'name': ' SUPERMAN ', 'description': 'Hero description', 'universe': 'x-men', 'imageUrl': 'https://image.com.br/image.jpg' } } response = self.app.post(path='/heroes', json=params) self.assertEqual(response.status_code, 500) self.assertEqual(response.get_json()['details'], 'Bad request, invalid universe') def test_create_hero_with_invalid_url(self): """Test create hero with invalid url""" params = { 'hero': { 'name': 'Superman', 'description': 'Superman description', 'universe': 'DC', 'imageUrl': '' } } response = self.app.post(path='/heroes', json=params) self.assertEqual(response.status_code, 500) self.assertEqual(response.get_json()['details'], 'Bad request, invalid image url') def test_create_hero_with_formatted_description(self): params = { 'hero': { 'name': 'SUPERMAN', 'description': ' hero description ', 'universe': 'DC', 'imageUrl': 'https://image.com.br/image.jpg' } } response = self.app.post(path='/heroes', json=params) self.assertEqual(response.status_code, 200) # Obtendo o heroi no banco de dados para conferir a descrição hero_updated = Hero.get_hero(response.get_json()['id']) self.assertEqual(hero_updated.description, 'Hero description')
class TestSurveyService(unittest.TestCase): def setUp(self): super().setUp() self.client = MockFirestore() self.collection = self.client.collection('test_surveys') def tearDown(self): self.client.reset() super().tearDown() def test_get_all(self): # given survey_collection.get_all = mock.Mock() # when survey_service.get_all() # then assert survey_collection.get_all.call_count == 1 def test_get_by_id(self): # given survey_collection.get_by_id = mock.Mock() # when survey_service.get_by_id('mockSurveyId') # then survey_collection.get_by_id.assert_called_once_with('mockSurveyId') def test_get_doc_by_id(self): # given survey_collection.get_doc_by_id = mock.Mock() # when survey_service.get_doc_by_id('mockSurveyId') # then survey_collection.get_doc_by_id.assert_called_once_with('mockSurveyId') def test_delete_by_id(self): # given survey_collection.delete_by_id = mock.Mock() # when survey_service.delete_by_id('mockSurveyId') # then survey_collection.delete_by_id.assert_called_once_with('mockSurveyId') def test_set_form_data_copies_values_from_a_document(self): form = { 'field1': mock.Mock(data=None), 'field2': mock.Mock(data='value2'), 'field3': mock.Mock(data='untouched') } ref = self.collection.document() ref.set({'field1': 'something', 'field2': 'new_value2'}) doc = ref.get() survey_service.set_form_data(form, doc) self.assertEqual(form['field1'].data, 'something') self.assertEqual(form['field2'].data, 'new_value2') self.assertEqual(form['field3'].data, 'untouched') def test_zip_file_returns_user_readable_filename(self): survey_id = 'some_test_id' survey_dict = { 'surveyname': 'test survey', 'question1': 'q1 text', } filename, _ = survey_service.zip_file(survey_id, survey_dict) self.assertRegex(filename, '.*_test-survey.zip$') def test_zip_file_returns_nested_zips_with_content(self): survey_id = 'some_test_id' survey_dict = { 'surveyname': 'test survey', 'question1': 'q1 text', } _, data = survey_service.zip_file(survey_id, survey_dict) zf = zipfile.ZipFile(data) names = sorted([nzf.filename for nzf in zf.filelist]) self.assertRegex(names[0], '.*_test-survey_default_control.zip$') self.assertRegex(names[1], '.*_test-survey_default_expose.zip$') def test_write_html_template(self): segments = ['segment1', 'segment2', 'segment3'] survey_dict = {'question1': 'q1 text', 'answer1a': 'a1a test'} survey_service.render_template = mock.Mock( return_value='<html>placeholder</html>') zips = survey_service.write_html_template('id1', survey_dict, 'test_prefix', segments) self.assertEqual(len(zips), len(segments)) self.assertEqual(zips[0].filename, '/tmp/test_prefix_segment1.zip') self.assertEqual(zips[1].filename, '/tmp/test_prefix_segment2.zip') self.assertEqual(zips[2].filename, '/tmp/test_prefix_segment3.zip') def test_delete_tmp_zip_files(self): os.remove = mock.Mock() with tempfile.TemporaryDirectory() as tmpdir: zip1 = zipfile.ZipFile(tmpdir + 'mock-file-name.zip', 'w') zip2 = zipfile.ZipFile(tmpdir + 'mock-file-name2.zip', 'w') survey_service.delete_tmp_zip_files([zip1, zip2]) expected_calls = [mock.call(zip1.filename), mock.call(zip2.filename)] os.remove.assert_has_calls(expected_calls) assert os.remove.call_count == 2 def test_get_all_question_text(self): survey_dict = { 'question1': 'q1 text', 'question2': 'q2 text', } result = survey_service.get_all_question_text(survey_dict) self.assertEqual(result, ['q1 text', 'q2 text']) def test_get_all_question_text_includes_text_after_missed_questions(self): survey_dict = { 'question1': 'q1 text', 'question2': 'q3 text', } result = survey_service.get_all_question_text(survey_dict) self.assertEqual(result, ['q1 text', 'q3 text']) def test_get_question_json_converts_to_format_expected_by_creative(self): survey = { 'question1': 'q1 text', 'question1type': 'q1type', 'question1order': 'ORDERED', 'answer1a': 'a1a', 'answer1anext': 'end', 'answer1b': 'a1b', 'answer1bnext': '2', 'question2': 'q2 text', } json = survey_service.get_question_json(survey) self.assertDictEqual( json[0], { 'answersOrder': 'ORDERED', 'id': 1, 'text': 'q1 text', 'type': 'q1type', 'next_question': { 'A': 'end', 'B': '2' }, 'options': [ { 'id': 'A', 'role': 'option', 'text': 'a1a' }, { 'id': 'B', 'role': 'option', 'text': 'a1b' }, ] }) self.assertEqual(json[1]['text'], 'q2 text') def test_get_thank_you_text_default(self): text = survey_service.get_thank_you_text({'language': 'ms'}) self.assertEqual(text, 'Terima Kasih') def test_get_thank_you_text_defaults_to_english_if_no_lang(self): text = survey_service.get_thank_you_text({}) self.assertEqual(text, 'Thank You') def test_get_thank_you_text_defaults_to_english_if_unknown_lang(self): text = survey_service.get_thank_you_text({'language': 'ZZ'}) self.assertEqual(text, 'Thank You') def test_get_next_text_default(self): text = survey_service.get_next_text({'language': 'ja'}) self.assertEqual(text, '次へ') def test_get_next_text_defaults_to_english_if_no_lang(self): text = survey_service.get_next_text({}) self.assertEqual(text, 'Next') def test_get_next_text_defaults_to_english_if_unknown_lang(self): text = survey_service.get_next_text({'language': 'ZZ'}) self.assertEqual(text, 'Next') def test_get_comment_text_default(self): text = survey_service.get_comment_text({'language': 'zh'}) self.assertEqual(text, '选择所有适用的') def test_get_comment_text_defaults_to_english_if_no_lang(self): text = survey_service.get_comment_text({}) self.assertEqual(text, 'Choose all applicable') def test_get_comment_text_defaults_to_english_if_unknown_lang(self): text = survey_service.get_comment_text({'language': 'ZZ'}) self.assertEqual(text, 'Choose all applicable') def test_get_survey_responses_limits_to_given_survey(self): mock_bigquery_client = mock.create_autospec(bigquery.Client) survey_service.get_survey_responses(12345, client=mock_bigquery_client) query_call = mock_bigquery_client.query.mock_calls[0] sql = query_call.args[0] survey_param = query_call.kwargs['job_config'].query_parameters[0] self.assertRegex(sql, 'WHERE ID = @survey_id') self.assertEqual(survey_param.name, 'survey_id') self.assertEqual(survey_param.value, 12345) @mock.patch.object(survey_service, 'get_survey_responses') def test_download_responses(self, responses_mock): t1 = datetime.datetime.now() t2 = t1 + datetime.timedelta(hours=-1) responses_mock.return_value = pandas.DataFrame({ 'CreatedAt': [t1, t2], 'Segmentation': ['seg1', 'seg2'], 'Response': ['1:r1a', '1:r2b'] }) raw_csv = survey_service.download_responses(1) responses = list(csv.DictReader(raw_csv.splitlines())) self.assertEqual(responses[0]['Date'], str(t1)) self.assertEqual(responses[0]['Control/Expose'], 'seg1') self.assertEqual(responses[0]['Response 1'], 'r1a') self.assertEqual(responses[1]['Date'], str(t2)) self.assertEqual(responses[1]['Control/Expose'], 'seg2') self.assertEqual(responses[1]['Response 1'], 'r2b') @mock.patch.object(survey_service, 'get_survey_responses') def test_download_responses_with_multi_question_responses( self, responses_mock): responses_mock.return_value = pandas.DataFrame({ 'CreatedAt': [datetime.datetime.now()], 'Segmentation': ['seg1'], 'Response': ['1:r1a|2:r1b||4:r1e|'] }) raw_csv = survey_service.download_responses(surveyid=1234) responses = list(csv.DictReader(raw_csv.splitlines())) self.assertEqual(responses[0]['Response 1'], 'r1a') self.assertEqual(responses[0]['Response 2'], 'r1b') self.assertEqual(responses[0]['Response 3'], '') self.assertEqual(responses[0]['Response 4'], 'r1e') self.assertEqual(responses[0]['Response 5'], '') @mock.patch.object(survey_service, 'get_survey_responses') def test_download_responses_returns_empty_csv_with_no_responses( self, responses_mock): responses_mock.return_value = pandas.DataFrame({ 'CreatedAt': [], 'Segmentation': [], 'Response': [] }) raw_csv = survey_service.download_responses(surveyid=1234) self.assertEqual(raw_csv.strip(), 'Date,Control/Expose,Dimension 2') @mock.patch.object(survey_service, 'get_survey_responses') def test_get_brand_lift_results(self, responses_mock): responses_mock.return_value = pandas.DataFrame({ 'CreatedAt': 4 * [datetime.datetime.now()], 'Segmentation': ['expose', 'expose', 'control', 'control'], 'Response': ['1:A', '1:A', '1:A', '1:B'] }) results = survey_service.get_brand_lift_results(1) q1_expose_lift = results[0][0] q1_control_lift = results[0][1] q1_lift = results[0][2] # Expose group has A for 2/2 of answers self.assertEqual(1, q1_expose_lift[0]) # Expose group has B for 0/2 of answers self.assertEqual(0, q1_expose_lift[1]) # Control group has A for 1/2 of answers self.assertEqual(0.5, q1_control_lift[0]) # Control group has B for 1/2 of answers self.assertEqual(0.5, q1_control_lift[1]) # Answer A is 100% more likely in expose group self.assertEqual(1, q1_lift[0]) # Answer B is 100% less likely in expose group self.assertEqual(-1, q1_lift[1]) @mock.patch.object(survey_service, 'get_survey_responses') def test_get_brand_lift_results_with_multi_question_responses( self, responses_mock): responses_mock.return_value = pandas.DataFrame({ 'CreatedAt': 4 * [datetime.datetime.now()], 'Segmentation': ['expose', 'expose', 'control', 'control'], 'Response': ['1:A|2:A', '1:A|2:B', '1:A|2:B', '1:B|2:B'] }) results = survey_service.get_brand_lift_results(1) q2_expose_lift = results[1][0] q2_control_lift = results[1][1] q2_lift = results[1][2] # Expose group has A for 1/2 of answers self.assertEqual(0.5, q2_expose_lift[0]) # Expose group has B for 1/2 of answers self.assertEqual(0.5, q2_expose_lift[1]) # Control group has A for 0/2 of answers self.assertEqual(0, q2_control_lift[0]) # Control group has B for 2/2 of answers self.assertEqual(1, q2_control_lift[1]) # Answer A is infinitely more likely in expose group (since 0 in control) self.assertEqual(math.inf, q2_lift[0]) # Answer B is 50% less likely in expose group self.assertEqual(-0.5, q2_lift[1]) @mock.patch.object(survey_service, 'get_survey_responses') def test_get_brand_lift_results_with_no_responses(self, responses_mock): responses_mock.return_value = pandas.DataFrame({ 'CreatedAt': [], 'Segmentation': [], 'Response': [] }) results = survey_service.get_brand_lift_results(1) self.assertEqual(results, []) @mock.patch.object(survey_service, 'get_survey_responses') def test_get_brand_lift_results_corrects_segment_names(self, responses_mock): responses_mock.return_value = pandas.DataFrame({ 'CreatedAt': 3 * [datetime.datetime.now()], 'Segmentation': ['default_expose', 'default_expose', 'default_control'], 'Response': ['1:A', '1:A', '1:B'] }) results = survey_service.get_brand_lift_results(1) q1_expose_lift = results[0][0] q1_control_lift = results[0][1] # Expose group has A for 2/2 of answers self.assertEqual(1, q1_expose_lift[0]) # Expose group has B for 0/2 of answers self.assertEqual(0, q1_expose_lift[1]) # Control group has A for 0/1 of answers self.assertEqual(0, q1_control_lift[0]) # Control group has B for 1/1 of answers self.assertEqual(1, q1_control_lift[1])