在python中编写单元测试的好方法

时间:2016-12-21 21:59:57

标签: python unit-testing python-unittest

我只是“做”'应用程序在python 2.7中,我为此编写了一些单元测试。这是我第一次使用python单元测试,我只是想知道单元测试的想法。

  1. 有人可以告诉我,我是否朝着正确的方向前进?
  2. 如何改进此测试?
  3. 如何检查IndexError中的消息是否正确?为此(" IndexError(' 注意不存在')"或IndexError(&# 39; 返回多个条目'))
  4. App:

    # coding: utf-8
    from __future__ import unicode_literals
    from shutil import copyfile
    import json
    import os
    
    DATABASE = 'notes_data/notes.json'
    BOARDS = ['to do', 'in progress', 'done']
    
    
    class NotesManagerMixin(object):
    
        def count(self):
            return len(self.notes)
    
        def filter(self, *args, **kwargs):
            result = self.notes
            for key, value in kwargs.iteritems():
                result = [
                    note for note in result
                    if getattr(note, key, None) == value or 
                    note.message.startswith(str(value)) or 
                    note.message.endswith(str(value))
                ]
            return NotesQueryset(result)
    
        def get(self, *args, **kwargs):
            notes = self.filter(*args,**kwargs)
            if notes.count() == 0:
                raise IndexError('Note doesn\'t exist')
            elif notes.count() == 1:
                return notes[0]
            else:
                raise IndexError('Returned more then one entry')
    
        def first(self):
            return self.notes[0]
    
        def last(self):
            return self.notes[-1]
    
    
    class NotesQueryset(NotesManagerMixin):
    
        def __init__(self, notes):
            self.notes = [note for note in notes]
    
        def update(self, *args, **kwargs):
            for note in self.notes:
                for key, value in kwargs.items():
                    setattr(note, key, value)
                note.save()
            return self
    
    
    
        def delete(self):
            for note in self.notes:
                note.delete()
            return self
    
    
        def __getitem__(self, idx):
            return self.notes[idx]
    
        def __str__(self):
            return str(self.notes)
    
        def __repr__(self):
            return self.__str__()
    
    
    class NotesManager(NotesManagerMixin):
    
        def __init__(self):
            self.notes = []
    
        def __iter__(self):
            return self.next()
    
        def __generate_id(self):
            """
                Funkcja pomocnicza do pobrania pewnej wolnej wartości indexu.
            """
            try:
                return max(note.id for note in self.notes) + 1
            except ValueError:
                return 1
    
        def all(self):
            return NotesQueryset(self.notes)
    
        def add(self, idx, board, message):
            self.notes.append(Note(idx=idx, board=board, message=message))
    
        def create(self, board, message):
            note = Note(
                idx=self.__generate_id(),
                board=board,
                message=message
            )
            note.clean()
    
            self.notes.append(note)
            note.save()
    
            return note
    
        def next(self):
            for note in self.notes:
                yield note
    
        def to_dict(self):
            return [note.to_dict() for note in self.notes]
    
    
    class Note(object):
        objects = NotesManager()
    
        def __init__(self, idx, board, message):
            self.id = idx
            self.board = board
            self.message = message
    
        def __str__(self):
            return 'ID: {}, Board: {}, Message: {}'.format(
                self.id,
                self.board,
                self.message
            )
    
        def __repr__(self):
            return self.__str__()
    
        def clean(self):
            if not self.message:
                raise ValueError('Message is required')
    
            if self.board not in BOARDS:
                raise ValueError('Board "{}" doesn\'t exists'.format(self.board))
    
            if type(self.id) != int:
                raise ValueError('Note id "{}" is invalid'.format(self.id))
    
        def save(self):
            for key, note in enumerate(self.objects):
                if note.id == self.id:
                    self.objects.notes[key] = self
                    break
    
            with open(DATABASE, 'w') as database_file:
                json.dump(self.objects.to_dict(), database_file, indent=4)
    
            return True
    
        def delete(self):
            for key, note in enumerate(self.objects.notes):
                if note.id == self.id:
                    self.objects.notes.pop(key)
    
            with open(DATABASE, 'w') as database_file:
                json.dump(self.objects.to_dict(), database_file, indent=4) 
    
    
        def to_dict(self):
            return {
                'id': self.id,
                'message': self.message,
                'board': self.board
            }
    
    
    def load_initial_data():
    
        with open(DATABASE, 'r') as database_file:
            json_data = json.load(database_file, encoding='utf-8')
    
        for item in json_data:
            Note.objects.add(
                idx=item['id'],
                board=item['board'],
                message=item['message'],
            )
    
    
    load_initial_data()
    

    单元测试:

    import unittest
    from notes_manager_v2 import NotesQueryset, Note, load_initial_data, NotesManagerMixin
    
    class TestNotesQueryset(unittest.TestCase):
    
        def test_filter(self):
            actual = Note.objects.all().filter(board='in progress') # get all notes with board 'in progress'
            expected = []
            for note in Note.objects.all():
                if note.board == 'in progress':
                    expected.append(note)
            self.assertItemsEqual(actual, expected)
    
        def test_get(self):
            actual = [Note.objects.all().get(id=1)] # get note with method get
            expected = []
            for note in Note.objects.all(): # search note with index 1
                if note.id == 1:
                    expected.append(note)
            self.assertEqual(actual, expected)
    
        def test_get_fail_1(self):
            self.assertRaises(IndexError, lambda:Note.objects.all().get(id=9868976)) # thos note dont exist should raise IndexError
    
    
        def test_update(self):
            from_board = 'to do'
            to_board = 'done'
            before_change = Note.objects.filter(board=from_board) # use filter method to get all notes with board 'to do'
            actual = Note.objects.filter(board=from_board).update(board=to_board) # update all board 
            self.assertNotEqual(before_change, actual) # check for difference
            notes = Note.objects.all()
            for note in actual:
                self.assertIn(note, notes) # check notes are updated 
    
    
    
        def test_delete(self):
            to_delete = Note.objects.filter(id=2).delete() # find note with filter method and delete it 
            notes = Note.objects.all()
            self.assertNotIn(to_delete, notes) 
    
    
        def test_create(self):
            new_note = Note.objects.create(message='lorem ipsum', board='in progress') # create new note
            notes = Note.objects.all()
            self.assertIn(new_note, notes) # 
    
    
    
    
    
    
    if __name__ == '__main__':
        unittest.main()
    

1 个答案:

答案 0 :(得分:-1)

你看过文件了吗?见doctest。它们是将单元测试集成到python代码中的简单方法。另一种选择是unittest框架。