0 1 2
tip default
Branko Majic (branko) - 2 years ago 2018-01-04 21:04:56
branko@majic.rs
CONNT-34: Implemented base functional test class: - Added helper class to be used as common ancestor for all functional tests. - Added missing headers. - Updated hgignore file to exclude the geckodriver.log.
3 files changed with 155 insertions and 1 deletions:
↑ Collapse Diff ↑
...
 
@@ -8,4 +8,5 @@ tmp/
8 8
 
dist/
9 9
 
django_conntrackt.egg-info/
10 10
 
projtect/.coverage
11
 
test_binaries/
...
 
 No newline at end of file
11
 
test_binaries/
12
 
geckodriver.log
...
 
 No newline at end of file
 
new file 100644
1
 
# -*- coding: utf-8 -*-
2
 
#
3
 
# Copyright (C) 2017 Branko Majic
4
 
#
5
 
# This file is part of Django Conntrackt.
6
 
#
7
 
# Django Conntrackt is free software: you can redistribute it and/or modify it
8
 
# under the terms of the GNU General Public License as published by the Free
9
 
# Software Foundation, either version 3 of the License, or (at your option) any
10
 
# later version.
11
 
#
12
 
# Django Conntrackt is distributed in the hope that it will be useful, but
13
 
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
 
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
15
 
# details.
16
 
#
17
 
# You should have received a copy of the GNU General Public License along with
18
 
# Django Conntrackt.  If not, see <http://www.gnu.org/licenses/>.
19
 
#
 
new file 100644
1
 
# -*- coding: utf-8 -*-
2
 
#
3
 
# Copyright (C) 2017 Branko Majic
4
 
#
5
 
# This file is part of Django Conntrackt.
6
 
#
7
 
# Django Conntrackt is free software: you can redistribute it and/or modify it
8
 
# under the terms of the GNU General Public License as published by the Free
9
 
# Software Foundation, either version 3 of the License, or (at your option) any
10
 
# later version.
11
 
#
12
 
# Django Conntrackt is distributed in the hope that it will be useful, but
13
 
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
 
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
15
 
# details.
16
 
#
17
 
# You should have received a copy of the GNU General Public License along with
18
 
# Django Conntrackt.  If not, see <http://www.gnu.org/licenses/>.
19
 
#
20
 

	
21
 

	
22
 
# Standard library imports.
23
 
import os
24
 
import time
25
 

	
26
 
# Django imports.
27
 
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
28
 

	
29
 
# Third-party library imports.
30
 
from selenium.common.exceptions import WebDriverException
31
 
from selenium import webdriver
32
 

	
33
 

	
34
 
# Maximum amount of time to wait before assuming a test has
35
 
# failed. Used as default for functions that wait.
36
 
MAX_WAIT = 10
37
 

	
38
 
# Delay between subsequent runs of function when using the wait
39
 
# decorator.
40
 
EXECUTION_DELAY = 0.5
41
 

	
42
 
# Base directory where the tests are located at.
43
 
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
44
 

	
45
 
# Base directory where the test binaries are located at.
46
 
TEST_BINARIES_DIR = os.path.join(BASE_DIR, "..", "..", "test_binaries")
47
 

	
48
 
# Location of Firefox binary.
49
 
FIREFOX_BINARY = os.path.join(TEST_BINARIES_DIR, "firefox", "firefox")
50
 

	
51
 
# Location of geckodriver binary.
52
 
GECKODRIVER_BINARY = os.path.join(TEST_BINARIES_DIR, "geckodriver")
53
 

	
54
 

	
55
 
def wait(fn, execution_delay=EXECUTION_DELAY, max_wait=MAX_WAIT):
56
 
    """
57
 
    Decorator that will produce a wrapper function that will run the
58
 
    specified function repeatedly as long as all of the following
59
 
    conditions have been met:
60
 

	
61
 
    - Function throws either AssertionError or
62
 
      selenium.common.exceptions.WebDriverException.
63
 
    - Combined runtime of all function calls does not exceed the
64
 
      maximum wait time.
65
 

	
66
 
    As soon as the original function returns without any thrown
67
 
    exceptions, the wrapper function will return its result.
68
 

	
69
 
    If the function throws any other exception beyond the ones listed
70
 
    above, this exception will get propagated.
71
 

	
72
 
    Arguments:
73
 

	
74
 
      fn
75
 
        Function that should be run.
76
 

	
77
 
      max_wait
78
 
        Maximum time in seconds to wait for function to execute
79
 
        successfully.
80
 

	
81
 
      execution_delay
82
 
        Delay in seconds between subsequent function runs. Used to
83
 
        prevent high CPU usage.
84
 

	
85
 
    Returns:
86
 

	
87
 
      Wrapper function around passed-in function. The wrapper
88
 
      function, provided it executes without failure, returns the
89
 
      result of original function.
90
 
    """
91
 

	
92
 
    def modified_fn(*args, **kwargs):
93
 
        start_time = time.time()
94
 

	
95
 
        while True:
96
 
            try:
97
 
                return fn(*args, **kwargs)
98
 
            except (AssertionError, WebDriverException) as e:
99
 
                if time.time() - start_time > max_wait:
100
 
                    raise e
101
 
                time.sleep(execution_delay)
102
 

	
103
 
    return modified_fn
104
 

	
105
 

	
106
 
class FunctionalTest(StaticLiveServerTestCase):
107
 
    """
108
 
    Helper test class that provides some convenience when writing
109
 
    functional tests.
110
 

	
111
 
    During test set-up, the class will:
112
 

	
113
 
    - Set-up a browser instance, storing it in property self.browser.
114
 

	
115
 
    During the test tear-down, the class will:
116
 

	
117
 
    - Destroy the browser instance.
118
 

	
119
 
    In addition to this, the class provides a convenience method
120
 
    wait_for which can be used to wait for a function to execute
121
 
    within a time slot and assert something, as described for the wait
122
 
    decorator.
123
 
    """
124
 

	
125
 
    def setUp(self):
126
 
        self.browser = webdriver.Firefox(firefox_binary=FIREFOX_BINARY, executable_path=GECKODRIVER_BINARY)
127
 

	
128
 
    def tearDown(self):
129
 
        self.browser.quit()
130
 
        super(FunctionalTest, self).tearDown()
131
 

	
132
 
    @wait
133
 
    def wait_for(self, fn):
134
 
        return fn()
0 comments (0 inline, 0 general)