python自動化テスト三部作のunittestフレームワークの実現

17206 ワード

ついに11まで待って、時間があってブログを書いて、11のこの数日間の休暇を利用してこのシリーズのBloggerを書き終わるつもりです。
このシリーズの文章は本人が三つのブログを書くつもりです。
第一篇:python自動化テストフレームワークを紹介します。
第二編:djangoフレーム+requestライブラリを紹介して、インタフェーステストを実現します。
紹介はJenkinsを利用して持続的な集積を実現します。
今日は第一編に入ります。unittestフレームワークを紹介します。
一、unittest略述
unittestはpython言語のユニットテストの枠組みであり、pythonの公式文書では、unittestユニットテストのフレームワークを詳しく紹介しています。興味のある読者はhttps://www.python.org/docまで行けます。
ウェブサイトを検索しますこのブログでは、unittestユニットのテストフレームワークの自動化テストにおけるアプリケーションを紹介します。
unittestユニットのテストフレームワークは、テスト用のケースを作成し、テストキットを作成し、大量にテストケースを実行する方法を提供しています。pythonのインストールが成功した後、unittestユニットのテストフレームは直接に導入して使用できます。彼はpythonの標準ライブラリに属します。ユニットテストのフレームワークとして、unittestユニットテストのフレームワークもプログラムの最小モジュールをスピーディに行うテストです。自動化試験iでは、白箱テストは必要ないですが、使用言語のセルテストの枠組みを知っておかなければなりません。これは後のテストのために、用例組織の問題に出会います。関数式プログラミングと対象向けプログラミングはコードの再構成を提供しますが、作成した各テストケースに対して、実行を呼び出すために関数として作成することはできません。ユニットテストフレームワークを利用して、unittestのTestCaseを継承するクラスを作成できます。これにより、各TestCaseを最小のユニットと見なし、テストキットによって組織され、実行時に直接実行すればいいです。同時にテストレポートを導入することができます。unittest各コンポーネントの関係が
TestCase----------------TestFixture(ファームウェアをテストする)
𞓜
𞓜
𞓜
TestSuite(テストキット)--------------------------TestRunner(テスト実行)-------------->TestReport(テストレポート)

# TestCase
#  ,     unittest.TestCase
#    class   unittest.TestCase,        。  TestCase           ,           。
#          setUp()|setUpClass()、    run()、        tearDown()|tearDownClass()。
#    unittest.TestCase   ,         test  。      test       (    )。
二、ファームウェアをテストする(TestFixture)
unittestユニットのテストフレームワークでは、ファームウェアをテストして初期化動作を処理します。例えば、Baiduの検索をテストする前に、まずブラウザを開けて、Baiduのトップページに入ります。テストが終わったら、ブラウザを閉じる必要があります。ファームウェアをテストします。二つの実施形態があります。一つはテストの実施例ごとにファームウェアをテストします。もう一つは、いくつかの用例iがあっても、ファームウェアをテストするのは一回だけです。

#                 。
#                    ,             ,          、      ,            、        。
#         testfixture。

# setUp():    ,             ;
# tearDown():    ,             ;
# setUpClass():    @classmethod   ,  case       ,     ;
# tearDownClass():    @classmethod   ,  case         ;
1、テストファームウェアは毎回実行します。
unittestユニットテストフレームワークは、setUpというtearDownのテストファームウェアを提供します。以下では、一例を作成することによって、ファームウェアの実行方法をテストします。テストコードは以下の通りです。

import unittest

class Test1(unittest.TestCase):

 #          
 def setUp(self):
  print("      ")

 #          
 def tearDown(self):
  print("      ")

 def test_case1(self):
  print("test_case1")

 def test_case2(self):
  print("test_case2")


if __name__ == '__main__':
 unittest.main(verbosity=2)
実行結果は以下の通りです

彼の実行順序は、まずsetUp方法を実行し、具体的な用例を実行し、最後にtearDown方法を実行する。
2、ファームウェアのテストは一回だけ行います。
フック方法setUpとtearDownはよく使われていますが、自動化テストではシステムのテストケースが千本以上あります。毎回一回実行するsetUpとtearDown方法は大量の性能を消費します。unittestユニットテストフレームの中でもう一つのテストファームウェアを使ってこの問題を解決できます。彼はsetUpClassとtearwClass方法です。このテストファームウェアの方法はクラスの方法です。このテストファームウェアを使うには、いくつかの用例があっても、ファームウェアをテストするのは一回だけです。具体的なコードは以下の通りです。

import unittest

class Test1(unittest.TestCase):
 # def setUp(self):
 #  print("      ")
 #
 # def tearDown(self):
 #  print("      ")

 @classmethod
 def setUpClass(cls):
  print("         ")

 @classmethod
 def tearDownClass(cls):
  print("         ")

 def test_case1(self):
  print("test_case1")

 def test_case2(self):
  print("test_case2")


if __name__ == '__main__':
 unittest.main(verbosity=2)
結果は以下のとおりです

3、二つのテストファームウェアが共存しています。

import unittest


class Test1(unittest.TestCase):
 def setUp(self):
  print("      ")

 def tearDown(self):
  print("      ")

 @classmethod
 def setUpClass(cls):
  print("         ")

 @classmethod
 def tearDownClass(cls):
  print("         ")

 def test_case1(self):
  print("test_case1")

 def test_case2(self):
  print("test_case2")


if __name__ == '__main__':
 unittest.main(verbosity=2)
実行結果は以下の通りです

結果は、まず@classimethod装飾器に飾られたテストファームウェアを実行し、通常のテストファームウェアを実行していることを示しています。
三、テスト実行
以上の事例では、テストケースの実行はメイン関数で、unittestが呼び出したのはメーンで、コードは以下の通りです。TestProjramはまだクラスです。このクラスの構造関数を見に来てください。コードは以下の通りです。

main = TestProgram
TestProjramはまだクラスです。また、このクラスの構造関数を見てください。コードは以下の通りです。

class TestProgram(object):
 """A command-line program that runs a set of tests; this is primarily
  for making test modules conveniently executable.
 """
 # defaults for testing
 module=None
 verbosity = 1
 failfast = catchbreak = buffer = progName = warnings = None
 _discovery_parser = None

 def __init__(self, module='__main__', defaultTest=None, argv=None,
     testRunner=None, testLoader=loader.defaultTestLoader,
     exit=True, verbosity=1, failfast=None, catchbreak=None,
     buffer=None, warnings=None, *, tb_locals=False):
  if isinstance(module, str):
   self.module = __import__(module)
   for part in module.split('.')[1:]:
    self.module = getattr(self.module, part)
  else:
   self.module = module
  if argv is None:
   argv = sys.argv

  self.exit = exit
  self.failfast = failfast
  self.catchbreak = catchbreak
  self.verbosity = verbosity
  self.buffer = buffer
  self.tb_locals = tb_locals
  if warnings is None and not sys.warnoptions:
   # even if DeprecationWarnings are ignored by default
   # print them anyway unless other warnings settings are
   # specified by the warnings arg or the -W python flag
   self.warnings = 'default'
  else:
   # here self.warnings is set either to the value passed
   # to the warnings args or to None.
   # If the user didn't pass a value self.warnings will
   # be None. This means that the behavior is unchanged
   # and depends on the values passed to -W.
   self.warnings = warnings
  self.defaultTest = defaultTest
  self.testRunner = testRunner
  self.testLoader = testLoader
  self.progName = os.path.basename(argv[0])
  self.parseArgs(argv)
  self.runTests()
unittestモジュールに含まれるmainメソッドは、テストモジュールを動作可能なテストスクリプトに簡単に移行することができます。メインはunittest.TestLoaderクラスを使用してモジュール内のテスト用例を自動的に検索してロードします。TestProgram類のこの部分のコードは以下の通りです。

 def createTests(self):
  if self.testNames is None:
   self.test = self.testLoader.loadTestsFromModule(self.module)
  else:
   self.test = self.testLoader.loadTestsFromNames(self.testNames,
               self.module)
テスト用例を実行する時、Mainメソッドにverbosity=2を追加しました。コードは以下の通りです。

if __name__ == '__main__':
 unittest.main(verbosity=2)
verbosityの部分を説明します。verbosityではデフォルトは1です。0は実行するテスト総数と全体結果を表し、2は詳細な情報を表します。
四、テストセット、TestSuite

# TestSuite
#               ,      test         ?           ,         ?
#       ,    test  A-Z、a-z     。                 ,    testSuite。
#            ,    ,  testSuite。testsuite     testsuite。
#     addTest()  addTests() suite   。case         Suite        。
1、直接実行事例
私たちはfunc.pyというファイルで加減乗除の4つのテスト関数を定義します。

#Auther Bob
#--*--conding:utf-8 --*--
def add(a,b):
 return a + b
def minus(a,b):
 return a - b
def multi(a,b):
 return a * b
def divide(a,b):
 return a / b

myunittest.pyファイルで私たちのテストコードを定義します。ここでは断言を使って、後で紹介します。

from test1 import func

class Test2(unittest.TestCase):
 def setUp(self):
  print("    ")

 def tearDown(self):
  print("    ")

 def test_add(self):
  self.assertEqual(3,func.add(1,2))

 def test_minus(self):
  self.assertEqual(4,func.minus(5,1))

 def test_multi(self):
  self.assertEqual(4,func.multi(2,2))

 def test_divide(self):
  self.assertEqual(10,func.divide(100,10))


if __name__ == '__main__':
 unittest.main(verbosity=2)
実行結果は以下の通りです

2、テストキットに判例を追加する
上記の簡単なテストは二つの問題が発生します。testテスティングの実施手順を制御できますか?あるテストケースを実行したくないなら、スキップする方法がありますか?実行順序については、デフォルトではtestのA-Z、a-zの方法で実行されます。自分で作成した用例の前後関係で実行するには、testSuiteが必要です。複数のテストケースをまとめて実行するのがtestSuiteです。testsuiteは、testsuiteを含むこともできる。一般的にaddTest()またはaddTests()によってsuiteに追加される。caseの実行順序はSuiteに追加された順序と一致している。
テストキットTestSuiteを使うなら、先にテストコードを記入する必要がありますが、先に実行しないでください。
私たちは同じmyunittest.pyファイルで私たちのテストコードを定義します。

from test1 import func


class Test3(unittest.TestCase):
 def setUp(self):
  print("    ")

 def tearDown(self):
  print("    ")


 def test_add(self):
  self.assertEqual(3,func.add(1,2))


 def test_minus(self):
  self.assertEqual(4,func.minus(5,1))


 def test_multi(self):
  self.assertEqual(4,func.multi(2,2))

 def test_divide(self):
  self.assertEqual(10,func.divide(100,10))
私たちはテクストにいますsuit.pyファイルにテストケースを導入し、TestSuiteクラスのaddTests方法でテストケースをテストキットに追加します。

import unittest
from test1.myunittest import Test3
# from test1.myunittest2 import Test3 as t3



if __name__ == '__main__':
 #         
 
 #      TestSuite 
 suite = unittest.TestSuite()
 
 #             list 
 tests = [Test3("test_add"), Test3("test_minus"), Test3("test_multi"), Test3("test_divide")]
 
 #                 
 suite.addTests(tests)
 # t = [t3("test_add"), t3("test_minus"), t3("test_multi"), t3("test_divide")]
 # suite.addTests(tests)
 
 #           
 runner = unittest.TextTestRunner(verbosity=2)
 
 #               
 runner.run(suite)
以上のケースはファイルを追加したテストケースです。同じように複数のファイルのケースをテストキットに追加して、このテストキットを実行すればいいです。

import unittest
from test1.myunittest import Test3
from test1.myunittest2 import Test3 as t3



if __name__ == '__main__':
 #         

 #      TestSuite 
 suite = unittest.TestSuite()

 #             list 
 tests = [Test3("test_add"), Test3("test_minus"), Test3("test_multi"), Test3("test_divide")]

 #                 
 suite.addTests(tests)
 
 #                     
 t = [t3("test_add"), t3("test_minus"), t3("test_multi"), t3("test_divide")]
 suite.addTests(t)

 #           
 runner = unittest.TextTestRunner(verbosity=2)

 #               
 runner.run(suite)
上の実行方式はアウトプット結果をコンソールに出力します。結果をファイルに出力することもできます。

import unittest
from test1.myunittest import Test3
from test1.myunittest2 import Test3 as t3



if __name__ == '__main__':
 
 #      txt   
 suite = unittest.TestSuite()
 tests = [Test3("test_add"), Test3("test_minus"), Test3("test_multi"), Test3("test_divide")]
 suite.addTests(tests)
 t = [t3("test_add"), t3("test_minus"), t3("test_multi"), t3("test_divide")]
 suite.addTests(t)
 with open('UnittestTextReport.txt', 'a') as f:
  runner = unittest.TextTestRunner(stream=f, verbosity=2)
  runner.run(suite)
3、試験種別を直接試験キットに追加する
ケースを一つ追加しますか?それとも面倒くさいですか?テストセットに直接追加できます。
次の方法でテストクラスをロードします。

unittest.TestLoader().loadTestsFromTestCase(t3)

import unittest
from unittest import TestLoader

from test1 import myunittest

from test1.myunittest2 import Test3 as t3

if __name__ == '__main__':
 suite = unittest.TestSuite()
 loader = TestLoader()
 test_cases1 = unittest.TestLoader().loadTestsFromTestCase(t3)
 #       ,       unittest.TestCase       
 suite.addTests(test_cases1)
 runner = unittest.TextTestRunner(verbosity=2)
 runner.run(suite)
4、モジュールを直接試験キットにロードします。このモジュールに複数の種類がある場合、すべての種類のテスト事例をテストキットにロードします。

unittest.TestLoader().loadTestsFromModule(myunittest)

import unittest
from unittest import TestLoader

from test1 import myunittest

from test1.myunittest2 import Test3 as t3

if __name__ == '__main__':
 suite = unittest.TestSuite()
 loader = TestLoader()
 test_cases1 = unittest.TestLoader().loadTestsFromModule(myunittest)
 #        ,          case    
 suite.addTests(test_cases1)
 runner = unittest.TextTestRunner(verbosity=2)
 runner.run(suite)
みなさんにスクリーンショットを見せます。

5、テストケース名でテストセットに判例を追加する

test_cases1 = unittest.TestLoader().loadTestsFromName('test1.myunittest2.Test3.test_minus')
 

import unittest
from unittest import TestLoader

from test1 import myunittest

from test1.myunittest2 import Test3 as t3

if __name__ == '__main__':

 suite = unittest.TestSuite()
 loader = TestLoader()
 test_cases1 = unittest.TestLoader().loadTestsFromName('test1.myunittest2.Test3.test_minus')
 #     cese
 runner = unittest.TextTestRunner(verbosity=2)
 suite.addTests(test_cases1)
 runner.run(suite)
スクリーンショットを見て、カタログの構造を見せます。

五、実行例を無視する
実際のプロジェクトの中で、一部のケースはまだ実行する必要がないかもしれません。もしこのような問題があれば、どうすればいいですか?unittestフレームワークはすでに解決案を提供してくれました。
1、無条件にこのケースをスキップし、その装飾器で実行するケースを修正すると、このケースは無視されます。実行しません。

@unittest.skip("do not exec")

 @unittest.skip("do not exec")
 #           
 def test_add(self):
  self.assertEqual(3,func.add(1,2))
2、ある条件を満たしてからこのケースをスキップします。

@unittest.skipIf(4 > 3,"2 > 3 do not exec")

 @unittest.skipIf(4 > 3,"2 > 3 do not exec")
 #            
 def test_minus(self):
  self.assertEqual(4,func.minus(5,1))
3、ある条件を満たさないでケースをスキップする

@unittest.skipUnless(4 < 3,"hahah")

 @unittest.skipUnless(4 < 3,"hahah")
 #             
 def test_multi(self):
  self.assertEqual(4,func.multi(2,2))
4、私達も判例の中でこの判例を実行しないと定義できます。

 def test_divide(self):
  self.skipTest("wydd")
  self.assertEqual(10,func.divide(100,10))
六、断言する
実際のテスト結果と予想される結果が一致するかどうかを判断し、一致すればテストに合格すると断言します。したがって、自動化テストでは、断言できないテストケースは無効であり、機能自動化がすでに全部実現されており、各バージョンの反復でテストケースを実行する場合、実行の結果は権威である必要があります。つまり、自動化テストケースは機能性または論理性の問題がないべきです。自動化テストで一番避けられているのは自動化テストの用例ですが、テストされた機能は問題があります。自動化テストケースは回帰テストによく使われています。発見された問題は特に多くないです。もしテスト結果に機能上の問題があれば、人力を投入した自動化パラメータはあまり意味がありません。ですから、各テストケースには断言が必要です。テストの結果には二つの可能性があります。一つは実行通過、もう一つは実行失敗、つまり機能に問題があります。TestCase類ではastert方法を提供して失敗を確認し報告します。一般的な方法は以下の通りです。

self.assertEqual(3,func.add(1,2))
  #       
  
  self.assertNotEqual()
  #        
  
  self.assertTrue()
  #         True
  
  self.assertFalse()
  #         False
  
  self.assertIs()
  #         
  
  self.assertIsNot()
  #         
  
  self.assertIsNone()
  #      None
  
  self.assertIsNotNone()
  #       None
  
  self.assertIn()
  #         
  
  self.assertNotIn()
  #            
  
  self.assertIsInstance()
  #            
  
  self.assertNotIsInstance()
ここで、python自動化テスト三部作のunittestフレームワークの実現に関する記事を紹介します。python unittestフレームの内容については、以前の文章を検索したり、下記の関連記事を見たりしてください。これからもよろしくお願いします。