পাইথন ইউনিটেস্ট - বিপরীতে assertRaises?


374

আমি কোনও পরীক্ষা লিখতে চাই যে কোনও ব্যতিক্রম কোনও নির্দিষ্ট পরিস্থিতিতে উত্থাপিত হয়নি establish

এটি পরীক্ষা সহজবোধ্য যদি একটি ব্যতিক্রম হয় উত্থাপিত ...

sInvalidPath=AlwaysSuppliesAnInvalidPath()
self.assertRaises(PathIsNotAValidOne, MyObject, sInvalidPath) 

... তবে কিভাবে আপনি বিপরীতে করতে পারেন ।

এরকম কিছু আমি পরে যা করছি ...

sValidPath=AlwaysSuppliesAValidPath()
self.assertNotRaises(PathIsNotAValidOne, MyObject, sValidPath) 

6
আপনি পরীক্ষায় কাজ করার জন্য যা যা কিছু করতে পারেন সবসময়ই করতে পারেন could যদি এটি একটি ত্রুটি উত্থাপন করে তবে তা প্রদর্শিত হবে (ব্যর্থতার পরিবর্তে ত্রুটি হিসাবে গণ্য হবে)। অবশ্যই, এটি ধরে নিয়েছে যে এটি কোনও ত্রুটি কেবল সংজ্ঞায়িত ধরণের পরিবর্তে কোনও ত্রুটি বাড়ায় না। এগুলি বাদে আমার ধারণা, আপনাকে নিজের লেখা লিখতে হবে।
থমাস কে


দেখা যাচ্ছে যে আপনি আসলে assertNotRaisesএমন একটি পদ্ধতি প্রয়োগ করতে পারেন যা তার কোড / আচরণের 90% ভাগের কোডের assertRaisesপ্রায় 30 ডলার করে is বিস্তারিত জানার জন্য নীচে আমার উত্তর দেখুন ।
টেলিফোন করুন

আমি এটি চাই তাই আমি দুটি ফাংশনগুলির সাথে তুলনা hypothesisকরতে পারি যাতে নিশ্চিত হয়ে যায় যে তারা সমস্ত ধরণের ইনপুটগুলির জন্য একই আউটপুট উত্পাদন করে, যেখানে যে ক্ষেত্রে আসল ব্যতিক্রম উত্থাপন করে তা উপেক্ষা করে। assume(func(a))কাজ করে না কারণ আউটপুট অস্পষ্ট সত্যের মান সহ একটি অ্যারে হতে পারে। সুতরাং আমি কেবল একটি ফাংশন কল করতে এবং Trueএটি ব্যর্থ না হলে পেতে চাই। assume(func(a) is not None)আমি অনুমান করি কাজগুলি
এন্ডোলিথ

উত্তর:


394
def run_test(self):
    try:
        myFunc()
    except ExceptionType:
        self.fail("myFunc() raised ExceptionType unexpectedly!")

32
@ হাইওলন - না, এটি আসলে সঠিক সমাধান। ব্যবহারকারী 9876 দ্বারা প্রস্তাবিত সমাধানটি ধারণাগতভাবে ত্রুটিযুক্ত: আপনি যদি না বলার জন্য পরীক্ষা করে থাকেন ValueError, তবে ValueErrorপরিবর্তে উত্থাপিত হয়, আপনার পরীক্ষাটি অবশ্যই একটি ব্যর্থতা নয়, ব্যর্থতার শর্তে প্রস্থান করতে হবে। অন্যদিকে, যদি একই কোড চালাতে আপনি একটি উত্থাপন করবেন KeyError, এটি একটি ত্রুটি হবে, ব্যর্থতা নয়। পাইথনে - অন্য কয়েকটি ভাষার চেয়ে আলাদা - ব্যতিক্রমগুলি নিয়মিতভাবে প্রবাহ নিয়ন্ত্রণের জন্য ব্যবহৃত হয়, এ কারণেই আমাদের except <ExceptionName>বাক্য গঠনটি প্রকৃতপক্ষে রয়েছে। সেই বিষয়ে, ব্যবহারকারী 9876 এর সমাধানটি কেবল ভুল।
ম্যাক

@ ম্যাক - এটিও কি সঠিক সমাধান? stackoverflow.com/a/4711722/6648326
MasterJoe2

এইগুলির মধ্যে পরীক্ষার জন্য <100% কভারেজ (বাদে কখনই ঘটবে না) দেখানোর দুর্ভাগ্যজনক প্রভাব রয়েছে।
শে

3
@ শায়, আইএমও আপনার সর্বদা পরীক্ষার ফাইলগুলি কভারেজ রিপোর্ট থেকে নিজেকে বাদ দেওয়া উচিত (যেহেতু তারা প্রায়শই সংজ্ঞা অনুসারে 100% চালিত হয়, আপনি কৃত্রিমভাবে প্রতিবেদনগুলি স্ফীত করে দেবেন)
মূল বিবিকিউ সস

@ অরিজিনাল-বিবিকিউ-সস, তা কি আমাকে অনিচ্ছাকৃত পরীক্ষার জন্য উন্মুক্ত রাখবে না? উদাহরণস্বরূপ, পরীক্ষার নামে টাইপো (ttst_function), পাইচার্মে ভুল রান কনফিগারেশন ইত্যাদি?
Shay

67

হাই - আমি কোনও পরীক্ষা লিখতে চাই তা নিশ্চিত করার জন্য যে কোনও ব্যতিক্রম কোনও নির্দিষ্ট পরিস্থিতিতে উত্থাপিত হয়নি।

এটি ডিফল্ট অনুমান - ব্যতিক্রম উত্থাপিত হয় না।

আপনি যদি আর কিছু না বলেন, এটি প্রতিটি পরীক্ষায় অনুমান করা হয়।

আপনাকে আসলে এটির জন্য কোনও দৃ write়তা লিখতে হবে না।


7
@ ইন্দ্রধনুশ গুপ্তা ভালভাবে গৃহীত উত্তর পরীক্ষাটির চেয়ে পরীক্ষাকে আরও অজগর করে তোলে। সুস্পষ্ট বর্ণিত চেয়ে ভাল।
0xc0de

17
অন্য কোনও মন্তব্যকারী এই উত্তর কেন ভুল তা উল্লেখ করেন নি , যদিও এটি একই কারণেই ব্যবহারকারীর 8৮76 এর উত্তরটি ভুল: ব্যর্থতা এবং ত্রুটি পরীক্ষা কোডের বিভিন্ন জিনিস। আপনার ফাংশন যদি ছিল একটি পরীক্ষা না জাহির করে সময় একটি ব্যতিক্রম নিক্ষেপ করা, পরীক্ষা ফ্রেমওয়ার্ক আচরণ করবেন যে যেমন ত্রুটি , বরং জাহির না একটি ব্যর্থতা নয়।
coredumperror

@ কোরডাম্প ইরর আমি একটি ব্যর্থতা এবং ত্রুটির মধ্যে পার্থক্য বুঝতে পেরেছি, তবে এটি কি আপনাকে চেষ্টা / ব্যতিক্রমী নির্মাণের সাথে প্রতিটি পরীক্ষাকে ঘিরে ফেলতে বাধ্য করবে না ? অথবা আপনি কেবল সেই পরীক্ষার জন্য সুপারিশ করবেন যা স্পষ্টভাবে কিছু শর্তের অধীনে ব্যতিক্রম উত্থাপন করে (যার মূল অর্থ ব্যতিক্রমটি প্রত্যাশিত )।
ফেডারিকোজাসন

4
@ ফেডেরিকোজাসন আপনি নিজের প্রশ্নের উত্তরটি দ্বিতীয় বাক্যে বেশ ভাল দিয়েছিলেন। পরীক্ষায় ব্যর্থতা বনাম ব্যর্থতা যথাক্রমে "অপ্রত্যাশিত ক্র্যাশ" বনাম "অযৌক্তিক আচরণ" হিসাবে সংক্ষিপ্তভাবে বর্ণনা করা যায়। আপনার ফাংশন ক্রাশ হওয়ার পরে আপনি নিজের পরীক্ষাগুলি একটি ত্রুটি দেখাতে চান, তবে যখন কোনও ইনপুট আপনি জানেন যে এটি নির্দিষ্ট ইনপুট নিক্ষেপ করবে তখন আলাদা ইনপুট দেওয়ার সময় নিক্ষিপ্ত হবে not
coredumperror

52

শুধু ফাংশন কল। যদি এটি একটি ব্যতিক্রম উত্থাপন করে তবে ইউনিট পরীক্ষার কাঠামো এটিকে ত্রুটি হিসাবে চিহ্নিত করবে। আপনি একটি মন্তব্য যুক্ত করতে পছন্দ করতে পারেন, যেমন:

sValidPath=AlwaysSuppliesAValidPath()
# Check PathIsNotAValidOne not thrown
MyObject(sValidPath)

35
ব্যর্থতা এবং ত্রুটি ধারণাগতভাবে পৃথক। তদ্ব্যতীত, পাইথন ব্যতিক্রমগুলি নিয়মিতভাবে প্রবাহের জন্য ব্যবহৃত হয়, তাই আপনি যদি নিজের যুক্তি বা আপনার কোডটি ভঙ্গ করে থাকেন তবে এক নজরে (= পরীক্ষার কোডটি অন্বেষণ না করে) এটি বুঝতে খুব অসুবিধা হবে ...
ম্যাক

1
হয় আপনার পরীক্ষা পাস হয় বা হয় না। যদি এটি পাস না করে তবে আপনাকে এটি ঠিক করতে হবে। এটি "ব্যর্থতা" বা "ত্রুটি" হিসাবে রিপোর্ট করা বেশিরভাগই অপ্রাসঙ্গিক। একটি পার্থক্য আছে: আমার উত্তর দিয়ে আপনি স্ট্যাকের ট্রেস দেখতে পাবেন যাতে আপনি দেখতে পাবেন যেখানে প্যাথআইএসএনটিএভালিডন নিক্ষেপ করা হয়েছিল; গৃহীত উত্তরের সাথে আপনার কাছে সেই তথ্য থাকবে না তাই ডিবাগিং আরও শক্ত হবে। (পাই 2 ধরে ধরে; পি 3 এটি আরও ভাল কিনা তা নিশ্চিত নন)।
ব্যবহারকারী9876

19
@ ব্যবহারকারী9876 - না। পরীক্ষার প্রস্থান শর্তাবলী 3 (পাস / নোপাস / ত্রুটি), আপনি 2 হিসাবে ভুল হিসাবে বিশ্বাস করছেন বলে মনে হচ্ছে না। ত্রুটি এবং ব্যর্থতার মধ্যে পার্থক্য যথেষ্ট এবং তাদের সাথে আচরণ করা যেমন তারা ঠিক তেমনি খারাপ প্রোগ্রামিং। আপনি যদি আমাকে বিশ্বাস না করেন তবে পরীক্ষামূলকভাবে রানাররা কীভাবে কাজ করে এবং কোন ব্যর্থতা এবং ত্রুটিগুলি তারা কী সিদ্ধান্ত গ্রহণ করে তা প্রায় ঘুরে দেখুন। পাইথন জন্য একটি ভাল শুরু হয় প্রসাধক pytest হবে। xfail
ম্যাক

4
আমার ধারণা এটি আপনি ইউনিট পরীক্ষাগুলি কীভাবে ব্যবহার করেন তার উপর নির্ভর করে। আমার দল যেভাবে ইউনিট পরীক্ষাগুলি ব্যবহার করে, তাদের অবশ্যই পাস করতে হবে। (চৌকস প্রোগ্রামিং, অবিচ্ছিন্ন ইন্টিগ্রেশন মেশিন সহ যা সমস্ত ইউনিট পরীক্ষা চালায়)। আমি জানি যে পরীক্ষার কেসটি "পাস", "ব্যর্থ" বা "ত্রুটি" প্রতিবেদন করতে পারে। তবে একটি উচ্চ স্তরে আসলে আমার দলের কাছে গুরুত্বপূর্ণ বিষয়টি কী "সমস্ত ইউনিট পরীক্ষা পাস করে?" (অর্থাত্ "জেনকিনস কি সবুজ?")। সুতরাং আমার দলের জন্য, "ব্যর্থ" এবং "ত্রুটি" এর মধ্যে কোনও ব্যবহারিক পার্থক্য নেই। আপনি যদি আলাদাভাবে নিজের ইউনিট পরীক্ষাগুলি ব্যবহার করেন তবে আপনার বিভিন্ন প্রয়োজনীয়তা থাকতে পারে।
user9876

1
@ user9876 'ব্যর্থ' এবং 'ত্রুটি' এর মধ্যে পার্থক্য হ'ল "আমার দৃ failed় ব্যর্থতা" এবং "আমার পরীক্ষা এমনকি দৃsert়তার কাছে পৌঁছায় না" " এটি, আমার কাছে, ফিক্সিং পরীক্ষার সময় একটি দরকারী পার্থক্য, তবে আমি অনুমান করি, যেমন আপনি বলেছেন, সবার জন্য নয়।
সিএস

14

আমি মূল পোস্টার এবং আমি ডিজিএইচ দ্বারা উপরের উত্তরটি কোডটিতে প্রথমে ব্যবহার না করেই গ্রহণ করেছি।

একবার আমি ব্যবহার করে বুঝলাম যে এটি করার জন্য আমার যা প্রয়োজন তা করার জন্য এটির জন্য কিছুটা টুইট করার দরকার ছিল (ডিজিএইচ-এর সাথে ন্যায্য হওয়ার জন্য তিনি "বা এই জাতীয় কিছু বলেছেন") "

আমি ভেবেছিলাম অন্যের উপকারের জন্য এখানে টুইটটি পোস্ট করা ভাল:

    try:
        a = Application("abcdef", "")
    except pySourceAidExceptions.PathIsNotAValidOne:
        pass
    except:
        self.assertTrue(False)

আমি এখানে যা করার চেষ্টা করছি তা হ'ল এটি নিশ্চিত করা যে যদি কোনও অ্যাপ্লিকেশন অবজেক্টকে দ্বিতীয় আর্গুমেন্টের সাথে পাইসোর্সএডএক্সেপশন সহ ইনস্ট্যান্ট করার চেষ্টা করা হয়েছিল athপথআইএসএনটিএভিডিঅন উত্থাপিত হবে।

আমি বিশ্বাস করি যে উপরের কোডটি (ডিজিএইচের উত্তরের উপর ভিত্তি করে) এটি করবে।


2
যেহেতু আপনি আপনার প্রশ্নটি পরিষ্কার করছেন এবং এর জবাব দিচ্ছেন না সেহেতু আপনার এটি সম্পাদনা করা উচিত ছিল (উত্তর দেওয়া হয়নি)। দয়া করে নীচে আমার উত্তর দেখুন see
হাইওয়েলন

13
এটি মূল সমস্যার থেকে সম্পূর্ণ বিপরীত বলে মনে হচ্ছে। self.assertRaises(PathIsNotAValidOne, MyObject, sInvalidPath)এই ক্ষেত্রে কাজ করা উচিত।
অ্যান্টনি হ্যাচকিন্স

8

আপনি সংজ্ঞায়িত করতে assertNotRaisesমূল বাস্তবায়ন 90% সম্পর্কে পুনঃব্যবহার দ্বারা assertRaisesমধ্যে unittestমডিউল। এই পদ্ধতির সাথে, আপনি একটি assertNotRaisesবিপরীত ব্যর্থতা শর্ত বাদে একই পদ্ধতিতে আচরণ করেন এমন একটি পদ্ধতি শেষ করেন assertRaises

টিএলডিআর এবং লাইভ ডেমো

এতে আশ্চর্যজনকভাবে কোনও assertNotRaisesপদ্ধতি যুক্ত করা সহজ হয়ে গেছে unittest.TestCase(কোডটি যেমন করছিল ঠিক তেমন উত্তরটি লিখতে আমাকে প্রায় 4 বার সময় লেগেছে)। এখানে কর্মের পদ্ধতিটির একটি লাইভ ডেমো রয়েছেassertNotRaises । শুধু মতassertRaises , হয় আপনি একটি callable এবং args পাস করতে পারেন assertNotRaises, অথবা আপনি একটি এটি ব্যবহার করতে পারেন withবিবৃতি। লাইভ ডেমোতে একটি পরীক্ষার কেস অন্তর্ভুক্ত রয়েছে যা এটি দেখায় যে এটি assertNotRaisesকাজ করে।

বিস্তারিত

বাস্তবায়ন assertRaisesমধ্যে unittestমোটামুটি জটিল কিন্তু চালাক subclassing একটি সামান্য বিট সঙ্গে আপনি ওভাররাইড করতে ও তার ব্যর্থতা শর্ত বিপরীত পারবেন না।

assertRaisesএকটি স্বল্প পদ্ধতি যা মূলত কেবল unittest.case._AssertRaisesContextশ্রেণীর একটি উদাহরণ তৈরি করে এবং এটি প্রদান করে ( unittest.caseমডিউলে এটির সংজ্ঞা দেখুন )। _AssertNotRaisesContextসাবক্লাসিং _AssertRaisesContextএবং এর __exit__পদ্ধতিটি ওভাররাইড করে আপনি নিজের শ্রেণীর সংজ্ঞা দিতে পারেন :

import traceback
from unittest.case import _AssertRaisesContext

class _AssertNotRaisesContext(_AssertRaisesContext):
    def __exit__(self, exc_type, exc_value, tb):
        if exc_type is not None:
            self.exception = exc_value.with_traceback(None)

            try:
                exc_name = self.expected.__name__
            except AttributeError:
                exc_name = str(self.expected)

            if self.obj_name:
                self._raiseFailure("{} raised by {}".format(exc_name,
                    self.obj_name))
            else:
                self._raiseFailure("{} raised".format(exc_name))

        else:
            traceback.clear_frames(tb)

        return True

সাধারণত আপনি পরীক্ষার কেস ক্লাসগুলি উত্তরাধিকার সূত্রে প্রাপ্ত করে সংজ্ঞায়িত করেন TestCase। পরিবর্তে আপনি যদি একটি সাবক্লাস থেকে উত্তরাধিকারী হন MyTestCase:

class MyTestCase(unittest.TestCase):
    def assertNotRaises(self, expected_exception, *args, **kwargs):
        context = _AssertNotRaisesContext(expected_exception, self)
        try:
            return context.handle('assertNotRaises', args, kwargs)
        finally:
            context = None

আপনার পরীক্ষার সমস্ত ক্ষেত্রে এখন তাদের কাছে assertNotRaisesপদ্ধতি উপলব্ধ রয়েছে।


tracebackআপনার elseবিবৃতিতে আপনার কোথা থেকে আসছে?
NOhs

1
@ নোহস একটি অনুপস্থিত ছিল import। এটি ঠিক করা হয়েছে
টেলিফোনে

2
def _assertNotRaises(self, exception, obj, attr):                                                                                                                              
     try:                                                                                                                                                                       
         result = getattr(obj, attr)                                                                                                                                            
         if hasattr(result, '__call__'):                                                                                                                                        
             result()                                                                                                                                                           
     except Exception as e:                                                                                                                                                     
         if isinstance(e, exception):                                                                                                                                           
            raise AssertionError('{}.{} raises {}.'.format(obj, attr, exception)) 

আপনার যদি পরামিতিগুলি গ্রহণ করার প্রয়োজন হয় তবে এটি সংশোধন করা যেতে পারে।

মত কল

self._assertNotRaises(IndexError, array, 'sort')

1

আমি নীচে বানর-প্যাচকে দরকারী বলে মনে করেছি unittest:

def assertMayRaise(self, exception, expr):
  if exception is None:
    try:
      expr()
    except:
      info = sys.exc_info()
      self.fail('%s raised' % repr(info[0]))
  else:
    self.assertRaises(exception, expr)

unittest.TestCase.assertMayRaise = assertMayRaise

কোনও ব্যতিক্রমের অনুপস্থিতির জন্য পরীক্ষা করার সময় এটি উদ্দেশ্যটি স্পষ্ট করে:

self.assertMayRaise(None, does_not_raise)

এটি একটি লুপে পরীক্ষাও সহজতর করে, যা আমি প্রায়শই নিজেকে করতে দেখি:

# ValueError is raised only for op(x,x), op(y,y) and op(z,z).
for i,(a,b) in enumerate(itertools.product([x,y,z], [x,y,z])):
  self.assertMayRaise(None if i%4 else ValueError, lambda: op(a, b))

বানর-প্যাচ কী?
স্কটএমসিসি

1
এন.ইউইউইকিপিডিয়া.আর / উইকি / মনকি_প্যাচ দেখুন । আপনি যুক্ত assertMayRaiseকরার পরে unittest.TestSuiteএটি unittestলাইব্রেরির অংশ হিসাবে ভান করতে পারেন ।
অ্যান্ডি জাস্ট

0

আপনি যদি কোনও ব্যতিক্রম শ্রেণিতে পাস করেন assertRaises()তবে একটি প্রসঙ্গ পরিচালক সরবরাহ করা হবে। এটি আপনার পরীক্ষার পাঠযোগ্যতার উন্নতি করতে পারে:

# raise exception if Application created with bad data
with self.assertRaises(pySourceAidExceptions.PathIsNotAValidOne):
    application = Application("abcdef", "")

এটি আপনাকে আপনার কোডটিতে ত্রুটির ঘটনাগুলি পরীক্ষা করতে দেয়।

এই ক্ষেত্রে, আপনি PathIsNotAValidOneযখন অ্যাপ্লিকেশন কনস্ট্রাক্টরের কাছে অবৈধ পরামিতিগুলি পাস করবেন আপনি পরীক্ষা করছেন ।


1
না, ব্যতিক্রম হবে যদি প্রসঙ্গ ব্যবস্থাপক ব্লকের মধ্যে ব্যতিক্রম না উত্থাপিত হয়। সহজেই 'সেলফ.অ্যাসেটরাইজস (TypeError) দ্বারা পরীক্ষা করা যেতে পারে: টাইপ এরির বাড়ান' যা উত্তীর্ণ হয়।
ম্যাথু ট্রেভর

@ ম্যাথিউট্রেভর শুভ কল যেমন আমি মনে করি, টেস্টিং কোডটি সঠিকভাবে সম্পাদন করার চেয়ে, অর্থাত্ উত্থাপিত হয় না, আমি পরীক্ষার ত্রুটির ক্ষেত্রে পরামর্শ দিচ্ছিলাম। আমি সেই অনুযায়ী উত্তর সম্পাদনা করেছি। আশা করি লাল থেকে বেরিয়ে আসতে আমি +1 উপার্জন করতে পারি। :)
হাইওলন

দ্রষ্টব্য, এটিও পাইথন ২.7 এবং পরবর্তী: ডকস.পিথন.আর.

0

আপনি যে মত চেষ্টা করতে পারেন। চেষ্টা করুন: self.assertRaises (কিছুই নয়, ফাংশন, আরজি 1, আরজি 2) ব্যতীত: আপনি যদি কোড ব্লকটির ভিতরে না রাখেন তবে পাস ব্যতীত এটির ব্যর্থতার মধ্য দিয়ে যাবে 'অ্যাসেরেশনএরর: কোনওটি উত্থাপিত হয়নি "এবং পরীক্ষার কেস ব্যর্থ হবে Test যদি চেষ্টা করা হয় যা প্রত্যাশিত আচরণের মধ্যে প্রবেশ করান।


0

কোনও ত্রুটি ছাড়াই অবজেক্টটি আরম্ভ করা হয়েছে তা নিশ্চিত করার একটি সোজা ফরোয়ার্ড উপায় হ'ল অবজেক্টের ধরণের উদাহরণ পরীক্ষা করা।

এখানে একটি উদাহরণ:

p = SomeClass(param1=_param1_value)
self.assertTrue(isinstance(p, SomeClass))
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.