diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000..cfcb171 --- /dev/null +++ b/test/README.md @@ -0,0 +1,27 @@ +## Filmatyk - test suite + +### API tests +[`test.api`](test_api.py) performs tests of the `FilmwebAPI` class +([`filmweb.py`](../filmatyk/filmweb.py)) - fetching and parsing content from Filmweb. + +Testing the whole program would typically require logging in to Filmweb.pl, +which might get cumbersome after a while. +Therefore, tests are split into two convenient parts: online and offline. +The basic online interface test is tested first, during which data is fetched +and cached locally. +This allows the more detailed tests to run without the need for online connection, +instead these cached files are used as data source. + +#### Basic online test: `TestAPIBasics` + +Test class `TestAPIBasics` encapsulates tests of the most fundamental functionalities: +* logging in to Filmweb.pl, +* fetching raw HTML data. + +However, the most important one is the `fetch_save` test, which not only grabs online data, +but also **stores it locally** (in `test/assets`), to simplify performing other tests. +Since this activity prompts for a Filmweb.pl **log-in**, it is disabled by default. +However, it is **required** to execute this test at least once - +otherwise other tests will error out. +To do this: +`cd test && python test_api.py all` diff --git a/test/test_api.py b/test/test_api.py new file mode 100644 index 0000000..815b7e3 --- /dev/null +++ b/test/test_api.py @@ -0,0 +1,100 @@ +import functools +import getpass +import os +import sys +import unittest + +from bs4 import BeautifulSoup as BS + +sys.path.append(os.path.join('..', 'filmatyk')) +import containers +import filmweb + +class TestAPIBasics(unittest.TestCase): + """Test basic API funcionality: login & fetching raw HTML data from Filmweb. + + This test is skipped by default, as it requires obtaining a session (and that + requires logging in, which would become rather tedious when experimenting). + It however produces assets later used by other tests, therefore it is crucial + that it be run before any other tests at least once. + """ + noTests = True + + @classmethod + def setUpClass(self): + self.api = None + self.assets_path = 'assets' + + @classmethod + def storeAPI(self, api): + self.api = api + + def setUp(self): + """Ensure the tests are skipped if the flag is set.""" + if self.noTests: + self.skipTest(reason='Basics tests skipped by default!') + + @staticmethod + def login_callback(username, password, *args, **kwargs): + """Fake callback for FilmwebAPI, to pass instead of a GUI login handler. + + "username" and "password" must be supplied prior to passing to FilmwebAPI + by functools.partial (or similar). + """ + isOK, session = filmweb.FilmwebAPI.login(username, password) + if not isOK: + session = None + return (session, username) + + def test_01_login(self): + """Attempt to log in to Filmweb. Requires credentials.""" + username = input('Username: ').strip() + password = getpass.getpass().strip() + login_callback = functools.partial( + self.login_callback, + password=password, + ) + api = filmweb.FilmwebAPI(login_callback, username) + self.assertIsNotNone(api) + api.checkSession() + self.assertIsNotNone(api.session) + self.storeAPI(api) + + def test_02_fetch_one(self): + """Attempt to download a single page of movie ratings from Filmweb.""" + self.assertIsNotNone(self.api) + self.assertIsNotNone(self.api.session) + url = self.api.Constants.getUserMoviePage( + self.api.username, + page=1, + ) + page = self.api._FilmwebAPI__fetchPage(url) + text = page.prettify() + self.assertIsInstance(text, str) + self.assertGreater(len(text), 100 * 2 ** 10) + + def test_03_fetch_save(self): + """Attempt to download 3 pages of movie ratings from Filmweb. + + This also stores them as "assets" for other tests. + """ + N_PAGES = 3 + for i in range(N_PAGES): + url = self.api.Constants.getUserMoviePage(self.api.username, page=i+1) + page = self.api._FilmwebAPI__fetchPage(url) + path = os.path.join('assets', 'movies_{}.html'.format(i+1)) + with open(path, 'w', encoding='utf-8') as html: + text = page.prettify() + self.assertGreater(len(text), 100 * 2 ** 10) + html.write(text) + for i in range(N_PAGES): + self.assertIn('movies_{}.html'.format(i+1), os.listdir('assets')) + + +if __name__ == "__main__": + try: + TestAPIBasics.noTests = (sys.argv[1] != 'all') + del sys.argv[1] + except IndexError: + pass + unittest.main()