2016-08-08 78 views
0

Wenn ich einen Pytest-Unit-Test für einen CherryPy-Server mit einer Unterklasse cherrypy.helper.CPWebCase ausführe, wie kann ich Daten für das Session-Objekt festlegen? Ich versuchte nur anrufen cherrypy.session['foo']='bar' wie ich würde, wenn ich wirklich in einem cherrypy Anruf war, aber das gab nur ein "AttributeError: '_Serving' object has no attribute 'session'"Python - CherryPy testen - Sitzungsdaten setzen?

Als Referenz ein Testfall könnte wie folgt aussehen (gezogen von the CherryPy Docs mit kleinen Änderungen):

import cherrypy 
from cherrypy.test import helper 
from MyApp import Root 

class SimpleCPTest(helper.CPWebCase): 
    def setup_server(): 
     cherrypy.tree.mount(Root(), "/", {'/': {'tools.sessions.on': True}}) 

    setup_server = staticmethod(setup_server) 

    def check_two_plus_two_equals_four(self): 
     #<code to set session variable to 2 here> 
     # This is the question: How do I set a session variable? 
     self.getPage("/") 
     self.assertStatus('200 OK') 
     self.assertHeader('Content-Type', 'text/html;charset=utf-8') 
     self.assertBody('4') 

und der Handler könnte wie folgt aussehen (oder irgendetwas anderes, macht es überhaupt keinen Unterschied):

class Root: 
    @cherrypy.expose 
    def test_handler(self): 
     #get a random session variable and do something with it 
     number_var=cherrypy.session.get('Number') 
     # Add two. This will fail if the session variable has not been set, 
     # Or is not a number 
     number_var = number_var+2 
     return str(number_var) 

es ist sicher anzunehmen, dass die Config richtig ist, und Sitzungen wie erwartet.

Ich könnte natürlich eine CherryPy-Seite schreiben, die einen Schlüssel und Wert als Argumente nimmt, und legt dann den angegebenen Sitzungswert, und rufen Sie das aus meinem Testcode (EDIT: Ich habe das getestet, und es tut Arbeit). Das scheint jedoch klugig zu sein, und ich würde es wirklich nur auf Tests beschränken wollen, wenn ich diesen Weg gehen würde.

+0

Haben Sie 'cherrypy.tools.session' für Ihren Endpunkt aktiviert? Was ist der genaue Code von Ihrem Handler und Testfall, plz bieten Snippets. – webKnjaZ

+0

Ja, Sitzungen sind aktiviert - die App funktioniert, ich versuche nur, einen Test dafür zu schreiben. Mein Handler ist WAY to complex hier zu posten, bestehend aus Dutzenden von Dateien und Tausenden von Codezeilen (da dies sich nicht auf einen bestimmten Teil bezieht). Was den Testfall betrifft, frage ich mich: Welchen Code brauche ich in meinem Testfall, um einen Wert für das Session-Objekt festlegen zu können? Wenn es nicht helfen würde, wenn ich einen generischen Testfallcode posten würde? – ibrewster

+0

Könnten Sie bitte die minimale Version, die Sie Ihren Handler und Config, posten, mit der es möglich ist, ein solches Problem zu reproduzieren (all Ihre schwere Logik). Ich würde gerne sehen, wie du eine Sitzung mit meinen Augen einstellst. Für jetzt sieht der Test gut aus. Bitte überprüfen Sie auch die Version von CherryPy, die Sie verwenden. – webKnjaZ

Antwort

3

Was Sie versuchen zu erreichen, wird normalerweise als mocking bezeichnet.

Beim Ausführen von Tests sollten Sie einige der Ressourcen, auf die Sie zugreifen, normalerweise mit Dummy-Objekten "vortäuschen", die dieselbe Schnittstelle haben (Duck-Typ). Dies kann mit Affenflicken erreicht werden. Um diesen Prozess zu vereinfachen, können Sie unittest.mock.patch entweder als Kontextmanager oder als Methoden-/Funktionsdekorator verwenden.

finden Sie unter dem Arbeitsbeispiel mit Kontext-Manager Option:

==> MyApp.py < ==

import cherrypy 


class Root: 
    _cp_config = {'tools.sessions.on': True} 

    @cherrypy.expose 
    def test_handler(self): 
     # get a random session variable and do something with it 
     number_var = cherrypy.session.get('Number') 
     # Add two. This will fail if the session variable has not been set, 
     # Or is not a number 
     number_var = number_var + 2 
     return str(number_var) 

==> cp_test.py < ==

from unittest.mock import patch 

import cherrypy 
from cherrypy.test import helper 
from cherrypy.lib.sessions import RamSession 

from MyApp import Root 


class SimpleCPTest(helper.CPWebCase): 
    @staticmethod 
    def setup_server(): 
     cherrypy.tree.mount(Root(), '/', {}) 

    def test_check_two_plus_two_equals_four(self): 
     # <code to set session variable to 2 here> 
     sess_mock = RamSession() 
     sess_mock['Number'] = 2 
     with patch('cherrypy.session', sess_mock, create=True): 
      # Inside of this block all manipulations with `cherrypy.session` 
      # actually access `sess_mock` instance instead 
      self.getPage("/test_handler") 
     self.assertStatus('200 OK') 
     self.assertHeader('Content-Type', 'text/html;charset=utf-8') 
     self.assertBody('4') 

Jetzt können Sie den Test wie folgt sicher ausführen:

$ py.test -sv cp_test.py 
============================================================================================================ test session starts ============================================================================================================= 
platform darwin -- Python 3.5.2, pytest-2.9.2, py-1.4.31, pluggy-0.3.1 -- ~/.pyenv/versions/3.5.2/envs/cptest-pyenv-virtualenv/bin/python3.5 
cachedir: .cache 
rootdir: ~/src/cptest, inifile: 
collected 2 items 

cp_test.py::SimpleCPTest::test_check_two_plus_two_equals_four PASSED 
cp_test.py::SimpleCPTest::test_gc <- ../../.pyenv/versions/3.5.2/envs/cptest-pyenv-virtualenv/lib/python3.5/site-packages/cherrypy/test/helper.py PASSED 
+0

Natürlich! Überschreibe einfach das lokale Session-Objekt des cherrypy-Threads mit meinem eigenen, globalen Objekt! Natürlich müssen Sie sicherstellen, dass Sie * any * -Werte setzen, auf die Sie in der getesteten Funktion zugreifen müssen, nicht nur was Sie testen (da das * real * -Session-Objekt nicht mehr verfügbar ist), aber das ist unbedeutend. – ibrewster

+0

Ja, das ist richtig :) – webKnjaZ