¿Cómo puedo burlarse de sqlite3.Cursor

He estado sacándome el pelo tratando de averiguar cómo burlarse de la clase sqlite3.Cursor específicamente el método fetchall .

Considere el siguiente ejemplo de código

 import sqlite3 from mock import Mock, patch from nose.tools import assert_false class Foo: def check_name(name): conn = sqlite3.connect('temp.db') c = conn.cursor() c.execute('SELECT * FROM foo where name = ?', name) if len(c.fetchall()) > 0: return True return False @patch('sqlite3.Cursor.fetchall', Mock(return_value=['John', 'Bob'])) def test_foo(): foo = Foo() assert_false(foo.check_name('Cane')) 

La ejecución de nosetests en la nosetests da nosetests resultado ningún error divertido

 E ====================================================================== ERROR: temp.test_foo ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/koddsson/.virtualenvs/temp/lib/python2.7/site-packages/nose/case.py", line 197, in runTest self.test(*self.arg) File "/home/koddsson/.virtualenvs/temp/lib/python2.7/site-packages/mock.py", line 1214, in patched patching.__exit__(*exc_info) File "/home/koddsson/.virtualenvs/temp/lib/python2.7/site-packages/mock.py", line 1379, in __exit__ setattr(self.target, self.attribute, self.temp_original) TypeError: can't set attributes of built-in/extension type 'sqlite3.Cursor' ---------------------------------------------------------------------- Ran 1 test in 0.002s FAILED (errors=1) 

¿No debería ser capaz de burlarme del método fetchall o estoy haciendo algo horriblemente mal?

Tomaría el enfoque de parchar el sqlite3 importado en su módulo y luego trabajaré desde allí.

Supongamos que su módulo se llama what.py

Yo parchearía what.sqlite3 y luego me burlaría del valor de retorno de .connect().cursor().fetchall .

Aquí hay un ejemplo más completo:

 from mock import patch from nose.tools import assert_true, assert_false from what import Foo def test_existing_name(): with patch('what.sqlite3') as mocksql: mocksql.connect().cursor().fetchall.return_value = ['John', 'Bob'] foo = Foo() assert_true(foo.check_name('John')) 

He encontrado una manera de burlar sqlite3.Cursor en mis pruebas:

 cursor = MagicMock(Cursor) cursor.fetchall.return_value = [{'column1': 'hello', 'column2': 'world'}] 

Soy bastante nuevo en Python pero así es como lo hago en Java.

No puedes burlarte de todo y las bases de datos son particularmente difíciles. A menudo me parece que lo correcto (especialmente con Sqlite, ya que es muy fácil) es cargar una base de datos de prueba con datos simulados y usarlos en las pruebas (es decir, los dispositivos). Después de todo, lo que realmente necesita probar es si su código está accediendo y consultando la base de datos correctamente.

La pregunta que normalmente intenta responder en una prueba como esta es “Si hay datos X en la base de datos y ejecuto la consulta Y, ¿esa consulta devuelve Z como espero”, o en un nivel más alto? “Si paso el parámetro X a mi método, devuelve el valor Z (basado en obtener Y de la db) “.

En su ejemplo, la pregunta real es “¿Es SELECT * FROM foo where name = ? La consulta correcta en este método?” pero no lo contestas si te burlas de la respuesta.