2017-05-25 4 views
0

Ich erstelle ein Testmodul für eine Flask-Anwendung. In der Methode get() von Resource hole ich Daten von Mongo und iteriere dann durch sie, um Ausgabe zu erzeugen. Ich verspotte die find() Methode der Sammlung, um meine iterable zurückzugeben. Das Problem ist, dass innerhalb get(), wo ich durch das iterable durchlaufen, es überspringt, als ob es leer war. Also habe ich versucht, das iterable innerhalb des Tests zu durchlaufen, und ich kann erfolgreich die 3 dicts sehen, die es enthalten sollte.Python Mock Iterable (Art) funktioniert nicht

Klasse Eigenschaften:

class _TestAll(BaseAllReports): 
    collection = MagicMock() 
    bool_columns = ('bool1', 'bool2') 
    string_set_columns = ('string1', 'string2') 
    int_columns = ('int1', 'int2') 
    text_columns = ('text1', 'text2') 
    stats_columns = ('bool1', 'int1') 

Resource.get():

def get(self): 
    args = self.parser().parse_args() 
    search = self.search_doc(args) 

    docs = self.collection.find(search, {'_id': False}) 
    print(docs) 

    ids, total_hurt, total_dead = set(), 0, 0 
    stats = dict((x, {}) for x in self.stats_columns) 
    stats['month'] = {} 
    for d in docs: 
     print('get', d) 
     if d['id'] in ids: 
      continue 
     else: 
      ids.add(d['id']) 
     for s in self.stats_columns: 
      if s in self.bool_columns: 
       key = u'Sí' if d[s] else 'No' 
      else: 
       key = d[s] 
      number = stats[s].get(key, 0) + 1 
      stats[s][key] = number 

     month_key = d['timestamp'].strftime('%b') 
     month_summary = stats['month'].get(month_key, {'hurt': 0, 'dead': 0}) 
     month_summary['hurt'] += d['total_hurt'] 
     month_summary['dead'] += d['total_dead'] 
     stats['month'][month_key] = month_summary 

     total_hurt += d['total_hurt'] 
     total_dead += d['total_dead'] 
    return { 
     'incidents': len(ids), 
     'involved': docs.count(), 
     'affected': total_hurt + total_dead, 
     'hurt': total_hurt, 
     'dead': total_dead, 
     'stats': stats 
    } 

Testaufbau:

@classmethod 
def setUpClass(cls): 
    app.testing = True 
    cls.app = app.test_client() 
    cls.url = '/incidents' 
    cls.url_with_key = '/incidents?key=testKeyHash' 
    api.add_resource(_TestAll, cls.url) 

Test:

def test_get(self): 
    with patch('__main__._TestAll.collection.find') as search: 
     answer = [] 
     for i in range(3): 
      answer.append({ 
       'id': i, 
       'bool1': True, 'bool2': False, 
       'string1': 'test', 'string2': 'test', 
       'int1': 1, 'int2': 2, 
       'text1': 'test', 'text2': 'test', 
       'timestamp': datetime.now(), 'total_hurt': 1, 'total_dead': 0}) 
     search.__iter__.return_value = answer 
     search.return_value.count.return_value = len(answer) 
     response = self.app.get(self.url_with_key) 
     data = json.loads(response.data.decode()) 
     for i in search: 
      print('test', i) 
     print(data) 
     self.assertEqual(_TestAll.collection.find.call_count, 1) 
     self.assertIn('stats', data) 
     for s in _TestAll.stats_columns: 
      self.assertIn(s, data['stats']) 

Terminal-Ausgang:

<MagicMock name='find()' id='4423760080'> 
('test', {'timestamp': datetime.datetime(2017, 5, 25, 13, 3, 9, 255912), 'text2': 'test', 'text1': 'test', 'int1': 1, 'int2': 2, 'id': 0, 'bool1': True, 'bool2': False, 'total_hurt': 1, 'total_dead': 0, 'string2': 'test', 'string1': 'test'}) 
('test', {'timestamp': datetime.datetime(2017, 5, 25, 13, 3, 9, 255923), 'text2': 'test', 'text1': 'test', 'int1': 1, 'int2': 2, 'id': 1, 'bool1': True, 'bool2': False, 'total_hurt': 1, 'total_dead': 0, 'string2': 'test', 'string1': 'test'}) 
('test', {'timestamp': datetime.datetime(2017, 5, 25, 13, 3, 9, 255928), 'text2': 'test', 'text1': 'test', 'int1': 1, 'int2': 2, 'id': 2, 'bool1': True, 'bool2': False, 'total_hurt': 1, 'total_dead': 0, 'string2': 'test', 'string1': 'test'}) 
{u'stats': {u'bool1': {}, u'int1': {}, u'month': {}}, u'involved': 3, u'dead': 0, u'hurt': 0, u'incidents': 0, u'affected': 0} 

Ich verstehe nicht, warum die Ressourcen Schleife nicht richtig durch die iterable aber der Test kann nicht. Jede Hilfe wird geschätzt.

Dank

+0

Ich verstehe Ihre Frage nicht. Ich kann dein Problem nicht reproduzieren: 'x = MagicMock(); x .__ iter __. return_value = [1] 'für mich funktioniert ganz gut:' für y in x: print (y) 'ergibt' 1'. Bitte: Geben Sie ein ** vollständiges ** Beispiel an, mit dem wir Ihr Problem reproduzieren können. Es gibt wahrscheinlich noch etwas dazwischen, das Probleme verursacht ... – Bakuriu

+0

@Bakuriu Ich habe die Klasse und die Setup-Methode hinzugefügt. Ich habe andere Tests, aber ich habe sie auskommentiert und das Problem besteht fort, so dass diese nicht benötigt werden. Ich übergebe keine Argumente, also gibt search_doc() ein leeres dict zurück. Was würdest du sonst für relevant halten? – gamda

Antwort

0

Wenn die __iter__ Wert, war die Linie

search.__iter__.return_value = answer 

I berücksichtigt nicht die Tatsache, dass hat filter() aufrufbar war. Der richtige Weg zu erreichen, was ich versuche, ist:

search.return_value.__iter__.return_value = answer 

Da der search Mock genannt wurde, ein neues MagicMock zurückgegeben wurde, was natürlich nicht den __iter__ Eigenschaftssatz hat. Die get() der Quelle und die Testfunktion greifen auf verschiedene Mocks zu, weshalb sie nur auf einem davon funktioniert haben.

Die Art, wie ich herausgefunden habe, war, indem ich den Mock auch innerhalb der Testmethode druckte und eine andere Schein-ID dafür erhielt.