Best Python code snippet using httmock_python
test_login_facebook_index.py
Source:test_login_facebook_index.py
1import os2import json3from botocore.exceptions import ClientError4from unittest import TestCase5from unittest.mock import patch6from login_facebook_index import LoginFacebookIndex7from exceptions import FacebookOauthError8from tests_util import TestsUtil9dynamodb = TestsUtil.get_dynamodb_client()10class TestLoginFacebookIndex(TestCase):11 def setUp(self):12 os.environ['FACEBOOK_APP_ID'] = 'fake_client_id'13 os.environ['FACEBOOK_APP_SECRET'] = 'fake_secret'14 os.environ['FACEBOOK_APP_TOKEN'] = 'fake_token'15 os.environ['FACEBOOK_OAUTH_CALLBACK_URL'] = 'http://callback'16 os.environ['EXTERNAL_PROVIDER_LOGIN_COMMON_TEMP_PASSWORD'] = 'xxxxxxxx'17 os.environ['EXTERNAL_PROVIDER_LOGIN_MARK'] = 'xxxxx'18 os.environ['COGNITO_USER_POOL_ID'] = 'user_pool_id'19 os.environ['COGNITO_USER_POOL_APP_ID'] = 'user_pool_id'20 TestsUtil.set_all_tables_name_to_env()21 TestsUtil.delete_all_tables(dynamodb)22 external_provider_users_items = [23 {24 'external_provider_user_id': 'Facebook-1234',25 'user_display_name': 'test_display_name02',26 'email': 'test02@example.com',27 'password': 'test_pass',28 'iv': 'iv'29 },30 {31 'external_provider_user_id': 'Facebook-12345',32 'user_display_name': 'test_display_name02',33 'email': 'test02@example.com',34 'password': 'test_pass',35 'iv': 'iv',36 'user_id': 'user'37 }38 ]39 TestsUtil.create_table(dynamodb, os.environ['EXTERNAL_PROVIDER_USERS_TABLE_NAME'], external_provider_users_items)40 def assert_bad_request(self, params):41 response = LoginFacebookIndex(params, {}).main()42 self.assertEqual(response['statusCode'], 400)43 def test_validation_with_no_body(self):44 params = {45 'body': {}46 }47 params['body'] = json.dumps(params['body'])48 self.assert_bad_request(params)49 def test_validation_with_no_code(self):50 params = {51 'body': {52 'state': 'state'53 }54 }55 params['body'] = json.dumps(params['body'])56 self.assert_bad_request(params)57 def test_validation_with_no_state(self):58 params = {59 'body': {60 'code': 'code'61 }62 }63 params['body'] = json.dumps(params['body'])64 self.assert_bad_request(params)65 def test_main_ok_with_creating_new_user(self):66 with patch('login_facebook_index.FacebookUtil') as facebook_mock, \67 patch('login_facebook_index.UserUtil') as user_mock, \68 patch('login_facebook_index.CryptoUtil') as crypto_mock:69 facebook_mock.return_value.get_user_info.return_value = {70 'user_id': 'Facebook-1234',71 'email': 'Facebook-1234@example.com',72 }73 facebook_mock.return_value.get_access_token.return_value = {74 'access_token': 'access_token',75 'id_token': 'id_token'76 }77 crypto_mock.encrypt_password.return_value = '&yjgFwFeOpd0{0=&y566'78 facebook_mock.return_value.verify_state_nonce.return_value = True79 user_mock.exists_user.return_value = False80 user_mock.create_external_provider_user.return_value = {81 'AuthenticationResult': {82 'AccessToken': 'aaaaa',83 'IdToken': 'bbbbb',84 'RefreshToken': 'ccccc'85 }86 }87 user_mock.add_external_provider_user_info.return_value = None88 params = {89 'body': {90 'code': 'code',91 'state': 'state'92 }93 }94 params['body'] = json.dumps(params['body'])95 response = LoginFacebookIndex(params, {}).main()96 self.assertEqual(response['statusCode'], 200)97 self.assertEqual(98 json.loads(response['body']),99 {100 'access_token': 'aaaaa',101 'id_token': 'bbbbb',102 'refresh_token': 'ccccc',103 'last_auth_user': 'Facebook-1234',104 'has_user_id': False,105 'status': 'sign_up'106 }107 )108 def test_main_ok_with_existing_user_and_user_id(self):109 with patch('login_facebook_index.FacebookUtil') as facebook_mock, \110 patch('login_facebook_index.UserUtil') as user_mock, patch('login_facebook_index.CryptoUtil') as crypto_mock:111 facebook_mock.return_value.get_user_info.return_value = {112 'user_id': 'Facebook-12345',113 'email': 'Facebook-1234@example.com',114 'display_name': 'my_name'115 }116 facebook_mock.return_value.get_access_token.return_value = {117 'access_token': 'access_token',118 'id_token': 'id_token'119 }120 facebook_mock.return_value.verify_state_nonce.return_value = True121 crypto_mock.get_external_provider_password.return_value = 'password'122 user_mock.exists_user.return_value = True123 user_mock.has_user_id.return_value = True124 user_mock.get_user_id.return_value = 'user_id'125 user_mock.external_provider_login.return_value = {126 'AuthenticationResult': {127 'AccessToken': 'aaaaa',128 'IdToken': 'bbbbb',129 'RefreshToken': 'ccccc'130 }131 }132 params = {133 'body': {134 'code': 'code',135 'state': 'state'136 }137 }138 params['body'] = json.dumps(params['body'])139 response = LoginFacebookIndex(params, {}, dynamodb=dynamodb).main()140 self.assertEqual(response['statusCode'], 200)141 self.assertEqual(142 json.loads(response['body']),143 {144 'access_token': 'aaaaa',145 'id_token': 'bbbbb',146 'refresh_token': 'ccccc',147 'last_auth_user': 'user_id',148 'has_user_id': True,149 'status': 'login'150 }151 )152 user_mock.external_provider_login.assert_called_with(153 cognito=None,154 password='password',155 provider='xxxxx',156 user_id='user_id',157 user_pool_app_id='user_pool_id',158 user_pool_id='user_pool_id'159 )160 def test_main_ok_with_existing_user_and_no_user_id(self):161 with patch('login_facebook_index.FacebookUtil') as facebook_mock, \162 patch('login_facebook_index.UserUtil') as user_mock, patch('login_facebook_index.CryptoUtil') as crypto_mock:163 facebook_mock.return_value.get_user_info.return_value = {164 'user_id': 'Facebook-1234',165 'email': 'Facebook-1234@example.com',166 'display_name': 'my_name'167 }168 facebook_mock.return_value.get_access_token.return_value = {169 'access_token': 'access_token',170 'id_token': 'id_token'171 }172 facebook_mock.return_value.verify_state_nonce.return_value = True173 crypto_mock.get_external_provider_password.return_value = 'password'174 user_mock.exists_user.return_value = True175 user_mock.has_user_id.return_value = False176 crypto_mock.decrypt_password.return_value = 'password'177 user_mock.external_provider_login.return_value = {178 'AuthenticationResult': {179 'AccessToken': 'aaaaa',180 'IdToken': 'bbbbb',181 'RefreshToken': 'ccccc'182 }183 }184 params = {185 'body': {186 'code': 'code',187 'state': 'state'188 }189 }190 params['body'] = json.dumps(params['body'])191 response = LoginFacebookIndex(params, {}, dynamodb=dynamodb).main()192 self.assertEqual(response['statusCode'], 200)193 self.assertEqual(194 json.loads(response['body']),195 {196 'access_token': 'aaaaa',197 'id_token': 'bbbbb',198 'refresh_token': 'ccccc',199 'last_auth_user': 'Facebook-1234',200 'has_user_id': False,201 'status': 'login'202 }203 )204 user_mock.external_provider_login.assert_called_with(205 cognito=None,206 password='password',207 provider='xxxxx',208 user_id='Facebook-1234',209 user_pool_app_id='user_pool_id',210 user_pool_id='user_pool_id'211 )212 def test_main_ng_with_auth_error(self):213 with patch('login_facebook_index.FacebookUtil') as facebook_mock:214 facebook_mock.return_value.get_user_info.side_effect = FacebookOauthError(215 endpoint='http://example.com',216 status_code=400,217 message='{"error":{"message":"auth error"}}'218 )219 params = {220 'body': {221 'code': 'code',222 'state': 'state'223 }224 }225 params['body'] = json.dumps(params['body'])226 response = LoginFacebookIndex(params, {}).main()227 self.assertEqual(response['statusCode'], 401)228 self.assertEqual(229 json.loads(response['body']),230 {231 'message': 'auth error'232 }233 )234 def test_main_ng_with_facebookexception(self):235 with patch('login_facebook_index.FacebookUtil') as facebook_mock:236 facebook_mock.return_value.get_user_info.side_effect = FacebookOauthError(237 endpoint='http://example.com',238 status_code=500,239 message='error'240 )241 params = {242 'body': {243 'code': 'code',244 'state': 'state'245 }246 }247 params['body'] = json.dumps(params['body'])248 response = LoginFacebookIndex(params, {}).main()249 self.assertEqual(response['statusCode'], 500)250 self.assertEqual(251 json.loads(response['body']),252 {253 'message': 'Internal server error'254 }255 )256 def test_main_ng_with_invalid_state_and_existing_user(self):257 with patch('login_facebook_index.FacebookUtil') as facebook_mock, \258 patch('login_facebook_index.UserUtil') as user_mock, patch('login_facebook_index.CryptoUtil') as crypto_mock:259 facebook_mock.return_value.get_user_info.return_value = {260 'user_id': 'facebook-1234',261 'email': 'facebook-1234@example.com',262 'display_name': 'my_name'263 }264 facebook_mock.return_value.get_access_token.return_value = {265 'access_token': 'access_token',266 'id_token': 'id_token'267 }268 facebook_mock.return_value.verify_state_nonce.return_value = False269 crypto_mock.get_external_provider_password.return_value = 'password'270 user_mock.exists_user.return_value = True271 user_mock.has_user_id.return_value = True272 user_mock.external_provider_login.side_effect = ClientError(273 {'Error': {'Code': 'xxxxxx'}},274 'operation_name'275 )276 params = {277 'body': {278 'code': 'code',279 'state': 'state'280 }281 }282 params['body'] = json.dumps(params['body'])283 response = LoginFacebookIndex(params, {}).main()284 self.assertEqual(response['statusCode'], 500)285 self.assertEqual(286 json.loads(response['body']),287 {288 'message': 'Internal server error'289 }290 )291 def test_main_ng_with_awsexception_and_existing_user(self):292 with patch('login_facebook_index.FacebookUtil') as facebook_mock, \293 patch('login_facebook_index.UserUtil') as user_mock:294 facebook_mock.return_value.get_user_info.return_value = {295 'user_id': 'facebook-1234',296 'email': 'facebook-1234@example.com',297 'display_name': 'my_name'298 }299 user_mock.exists_user.return_value = True300 user_mock.has_user_id.return_value = True301 user_mock.external_provider_login.side_effect = ClientError(302 {'Error': {'Code': 'xxxxxx'}},303 'operation_name'304 )305 params = {306 'body': {307 'code': 'code',308 'state': 'state'309 }310 }311 params['body'] = json.dumps(params['body'])312 response = LoginFacebookIndex(params, {}).main()313 self.assertEqual(response['statusCode'], 500)314 self.assertEqual(315 json.loads(response['body']),316 {317 'message': 'Internal server error: LoginFacebookIndex'318 }319 )320 def test_main_ng_with_awsexception_and_new_user(self):321 with patch('login_facebook_index.FacebookUtil') as facebook_mock, \322 patch('login_facebook_index.UserUtil') as user_mock, patch('login_facebook_index.CryptoUtil') as crypto_mock:323 facebook_mock.return_value.get_user_info.return_value = {324 'user_id': 'facebook-1234',325 'email': 'facebook-1234@example.com',326 'display_name': 'my_name'327 }328 facebook_mock.return_value.get_access_token.return_value = {329 'access_token': 'access_token',330 'id_token': 'id_token'331 }332 facebook_mock.return_value.verify_state_nonce.return_value = True333 crypto_mock.get_external_provider_password.return_value = 'password'334 user_mock.exists_user.return_value = False335 user_mock.create_external_provider_user.return_value = ClientError(336 {'Error': {'Code': 'xxxxxx'}},337 'operation_name'338 )339 user_mock.force_non_verified_phone.return_value = None340 user_mock.add_user_profile.return_value = None341 user_mock.add_external_provider_user_info.return_value = None342 user_mock.has_user_id.return_value = True343 params = {344 'body': {345 'code': 'code',346 'state': 'state'347 }348 }349 params['body'] = json.dumps(params['body'])350 response = LoginFacebookIndex(params, {}).main()351 self.assertEqual(response['statusCode'], 500)352 self.assertEqual(353 json.loads(response['body']),354 {355 'message': 'Internal server error: LoginFacebookIndex'356 }...
tests.py
Source:tests.py
...19@remember_called20def google_mock_count(url, request):21 return 'Hello from Google'22@urlmatch(scheme='http', netloc=r'(.*\.)?facebook\.com$')23def facebook_mock(url, request):24 return 'Hello from Facebook'25@urlmatch(scheme='http', netloc=r'(.*\.)?facebook\.com$')26@remember_called27def facebook_mock_count(url, request):28 return 'Hello from Facebook'29@urlmatch(netloc=r'(.*\.)?google\.com$', path=r'^/$', method='POST')30@remember_called31def google_mock_store_requests(url, request):32 return 'Posting at Google'33@all_requests34def charset_utf8(url, request):35 return {36 'content': u'Motörhead'.encode('utf-8'),37 'status_code': 200,38 'headers': {39 'Content-Type': 'text/plain; charset=utf-8'40 }41 }42def any_mock(url, request):43 return 'Hello from %s' % (url.netloc,)44def dict_any_mock(url, request):45 return {46 'content': 'Hello from %s' % (url.netloc,),47 'status_code': 200,48 'http_vsn': 10,49 }50def example_400_response(url, response):51 r = requests.Response()52 r.status_code = 40053 r._content = b'Bad request.'54 return r55class MockTest(unittest.TestCase):56 def test_return_type(self):57 with HTTMock(any_mock):58 r = requests.get('http://domain.com/')59 self.assertTrue(isinstance(r, requests.Response))60 self.assertTrue(isinstance(r.content, binary_type))61 self.assertTrue(isinstance(r.text, text_type))62 def test_scheme_fallback(self):63 with HTTMock(unmatched_scheme, any_mock):64 r = requests.get('http://example.com/')65 self.assertEqual(r.content, b'Hello from example.com')66 def test_path_fallback(self):67 with HTTMock(unmatched_path, any_mock):68 r = requests.get('http://example.com/')69 self.assertEqual(r.content, b'Hello from example.com')70 def test_method_fallback(self):71 with HTTMock(unmatched_method, any_mock):72 r = requests.get('http://example.com/')73 self.assertEqual(r.content, b'Hello from example.com')74 def test_netloc_fallback(self):75 with HTTMock(google_mock, facebook_mock):76 r = requests.get('http://google.com/')77 self.assertEqual(r.content, b'Hello from Google')78 with HTTMock(google_mock, facebook_mock):79 r = requests.get('http://facebook.com/')80 self.assertEqual(r.content, b'Hello from Facebook')81 def test_400_response(self):82 with HTTMock(example_400_response):83 r = requests.get('http://example.com/')84 self.assertEqual(r.status_code, 400)85 self.assertEqual(r.content, b'Bad request.')86 def test_real_request_fallback(self):87 with HTTMock(any_mock):88 with HTTMock(google_mock, facebook_mock):89 r = requests.get('http://example.com/')90 self.assertEqual(r.status_code, 200)91 self.assertEqual(r.content, b'Hello from example.com')92 def test_invalid_intercept_response_raises_value_error(self):93 @all_requests94 def response_content(url, request):95 return -196 with HTTMock(response_content):97 self.assertRaises(TypeError, requests.get, 'http://example.com/')98 def test_encoding_from_contenttype(self):99 with HTTMock(charset_utf8):100 r = requests.get('http://example.com/')101 self.assertEqual(r.encoding, 'utf-8')102 self.assertEqual(r.text, u'Motörhead')103 self.assertEqual(r.content, r.text.encode('utf-8'))104 def test_has_raw_version(self):105 with HTTMock(any_mock):106 r = requests.get('http://example.com')107 self.assertEqual(r.raw.version, 11)108 with HTTMock(dict_any_mock):109 r = requests.get('http://example.com')110 self.assertEqual(r.raw.version, 10)111class DecoratorTest(unittest.TestCase):112 @with_httmock(any_mock)113 def test_decorator(self):114 r = requests.get('http://example.com/')115 self.assertEqual(r.content, b'Hello from example.com')116 @with_httmock(any_mock)117 def test_iter_lines(self):118 r = requests.get('http://example.com/')119 self.assertEqual(list(r.iter_lines()),120 [b'Hello from example.com'])121class AllRequestsDecoratorTest(unittest.TestCase):122 def test_all_requests_response(self):123 @all_requests124 def response_content(url, request):125 return {'status_code': 200, 'content': 'Oh hai'}126 with HTTMock(response_content):127 r = requests.get('https://example.com/')128 self.assertEqual(r.status_code, 200)129 self.assertEqual(r.content, b'Oh hai')130 def test_all_str_response(self):131 @all_requests132 def response_content(url, request):133 return 'Hello'134 with HTTMock(response_content):135 r = requests.get('https://example.com/')136 self.assertEqual(r.content, b'Hello')137class AllRequestsMethodDecoratorTest(unittest.TestCase):138 @all_requests139 def response_content(self, url, request):140 return {'status_code': 200, 'content': 'Oh hai'}141 def test_all_requests_response(self):142 with HTTMock(self.response_content):143 r = requests.get('https://example.com/')144 self.assertEqual(r.status_code, 200)145 self.assertEqual(r.content, b'Oh hai')146 @all_requests147 def string_response_content(self, url, request):148 return 'Hello'149 def test_all_str_response(self):150 with HTTMock(self.string_response_content):151 r = requests.get('https://example.com/')152 self.assertEqual(r.content, b'Hello')153class UrlMatchMethodDecoratorTest(unittest.TestCase):154 @urlmatch(netloc=r'(.*\.)?google\.com$', path=r'^/$')155 def google_mock(self, url, request):156 return 'Hello from Google'157 @urlmatch(scheme='http', netloc=r'(.*\.)?facebook\.com$')158 def facebook_mock(self, url, request):159 return 'Hello from Facebook'160 @urlmatch(query=r'.*page=test')161 def query_page_mock(self, url, request):162 return 'Hello from test page'163 def test_netloc_fallback(self):164 with HTTMock(self.google_mock, facebook_mock):165 r = requests.get('http://google.com/')166 self.assertEqual(r.content, b'Hello from Google')167 with HTTMock(self.google_mock, facebook_mock):168 r = requests.get('http://facebook.com/')169 self.assertEqual(r.content, b'Hello from Facebook')170 def test_query(self):171 with HTTMock(self.query_page_mock, self.google_mock):172 r = requests.get('http://google.com/?page=test')...
test_posters.py
Source:test_posters.py
1# -*- coding: utf-8 -*-2import os3import pytz4import responses5import telepot6import tweepy7from datetime import datetime8from django.test import TestCase9from core.exceptions import MeteoSangueException10from core.main import update_blood_groups, get_blood_group_list11from core.models import BloodGroup, Log12from core.posters import telegram_status, tweet_status, facebook_status13from core.posters_register import posters_register14from core.tasks import fetch_and_update15from mock import mock16from .utils import MockPhantomJS17class PostersTest(TestCase):18 @mock.patch('core.main.webdriver.PhantomJS', autospec = True)19 @mock.patch('core.posters.facebook.GraphAPI', autospec = True)20 def test_poster_with_tags_facebook(self, facebook_mock, phantom_driver):21 mock_body = open(os.path.join(os.path.dirname(__file__), 'data', 'crs_page.html')).read()22 posters_register._posters = []23 posters_register.register_poster(facebook_status, 'facebook_done')24 m = mock.Mock()25 m.put_photo.side_effect = mock.Mock(id='1')26 facebook_mock.return_value = m27 phantom_driver.return_value = MockPhantomJS(mock_body)28 self.assertEqual(len(Log.objects.all()), 0)29 meteo_fake_status = 'ð¨ Emergenza: A+ , A- , O+ , O- , B- , AB- , AB+\n'30 meteo_upload_fake = os.path.join(os.path.dirname(__file__), 'data', 'meteo_fake_upload.png')31 facebook_status(meteo_fake_status, meteo_upload_fake)32 self.assertEqual(m.put_wall_post.call_count, 0)33 self.assertEqual(m.put_photo.call_count, 1)34 self.assertEqual(35 m.put_photo.call_args[1]['tags'],36 '[{"tag_uid": "andrea.stagi"}, {"tag_uid": "patrick.arminio"}]'37 )38 @mock.patch('core.main.webdriver.PhantomJS', autospec = True)39 @mock.patch('core.posters.tweepy.OAuthHandler', autospec = True)40 @mock.patch('core.posters.tweepy.API', autospec = True)41 def test_poster_with_mentions_twitter(self, tweepy_mock, tweepy_oauth_mock, phantom_driver):42 mock_body = open(os.path.join(os.path.dirname(__file__), 'data', 'crs_page.html')).read()43 posters_register._posters = []44 posters_register.register_poster(tweet_status, 'twitter_done')45 m = mock.Mock()46 m.update_with_media.return_value = mock.Mock(id='1')47 tweepy_mock.return_value = m48 phantom_driver.return_value = MockPhantomJS(mock_body)49 fetch_and_update()50 self.assertEqual(m.update_status.call_count, 1)51 self.assertEqual(m.update_with_media.call_count, 1)52 m.update_status.assert_called_with(53 '@4stagi @patrick91 Nuovo bollettino meteo â¬',54 in_reply_to_status_id='1'55 )56 @mock.patch('core.main.webdriver.PhantomJS', autospec = True)57 @mock.patch('core.posters.tweepy.OAuthHandler', autospec = True)58 @mock.patch('core.posters.tweepy.API', autospec = True)59 @mock.patch('core.posters.telepot.Bot', autospec = True)60 @mock.patch('core.posters.facebook.GraphAPI', autospec = True)61 def test_post_on_exception(self, facebook_mock, telegram_mock, tweepy_mock, tweepy_oauth_mock, phantom_driver):62 # Twitter63 mock_body = open(os.path.join(os.path.dirname(__file__), 'data', 'crs_page.html')).read()64 posters_register._posters = []65 posters_register.register_poster(tweet_status, 'twitter_done')66 m = mock.Mock()67 m.update_with_media.side_effect = tweepy.TweepError('Error on Twitter')68 tweepy_mock.return_value = m69 phantom_driver.return_value = MockPhantomJS(mock_body)70 self.assertEqual(len(Log.objects.all()), 0)71 mock_body = open(os.path.join(os.path.dirname(__file__), 'data', 'crs_page.html')).read()72 fetch_and_update()73 self.assertFalse(Log.objects.all()[0].twitter_done)74 self.assertEqual(m.update_status.call_count, 0)75 self.assertEqual(m.update_with_media.call_count, 1)76 # Telegram77 Log.objects.all().delete()78 posters_register._posters = []79 posters_register.register_poster(telegram_status, 'telegram_done')80 m = mock.Mock()81 m.sendMessage.side_effect = telepot.exception.TelepotException('Error on Telegram')82 telegram_mock.return_value = m83 phantom_driver.return_value = MockPhantomJS(mock_body)84 self.assertEqual(len(Log.objects.all()), 0)85 mock_body = open(os.path.join(os.path.dirname(__file__), 'data', 'crs_page.html')).read()86 fetch_and_update()87 self.assertFalse(Log.objects.all()[0].telegram_done)88 self.assertEqual(m.sendMessage.call_count, 1)89 self.assertEqual(m.sendPhoto.call_count, 1)90 # Facebook91 Log.objects.all().delete()92 posters_register._posters = []93 posters_register.register_poster(facebook_status, 'facebook_done')94 m = mock.Mock()95 m.put_photo.side_effect = Exception('Error on Facebook')96 facebook_mock.return_value = m97 phantom_driver.return_value = MockPhantomJS(mock_body)98 self.assertEqual(len(Log.objects.all()), 0)99 mock_body = open(os.path.join(os.path.dirname(__file__), 'data', 'crs_page.html')).read()100 fetch_and_update()101 self.assertFalse(Log.objects.all()[0].facebook_done)102 self.assertEqual(m.put_wall_post.call_count, 0)...
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!