繁体   English   中英

在python unittest中定义一个一次性类

[英]defining a one-off class within python unittest

如果这是重复的操作,请随时关闭,但是到目前为止,我还没有看到任何类似的消息。 我更多地是来自“经典OOP”背景(例如Java,C#,C ++,PHP(如果您想将其称为OOP语言...)等),而我现在正在尝试掌握Python。

假设我们有一个这样定义的类:

class Foo:

  def __init__(self):
    self.stuff = self.defineStuff()

  def method1(self, x):
    return x

  def defineStuff(self):
    # this method has no logic in this class; child classes should define this
    pass

  def doStuff(self):
    return self.stuff

class FooTest(unittest.TestCase):
  def testMethod1(self):
    assertEquals(5, Foo().method1(5))

好的,到目前为止很好。 但是,我真正要测试的是doStuff可以正常工作; 上面的实现本身可能太琐碎了,但是我没有在这里发布我的实际代码。 由于doStuff依靠defineStuff来填充stuff成员变量,因此测试Foo.doStuff()是没有意义的,除非我要测试基类实现是否抛出AttributeError。 (这是有效的,但实际上不是我要测试的内容)。 但是,我可以执行以下操作:

class FooTest(unittest.TestCase):
  # we did this before, it's just here for reference
  def testMethod1(self):
    assertEquals(5, Foo().method1(5))

  def testDefineStuff(self):
    class Bar(Foo):
      def defineStuff(stuff):
        self.stuff = stuff
        return self
    bar = Bar().defineStuff('abcdefg')
    self.assertEquals('abcdefg', bar.stuff)

我已经尝试在setUp()方法中定义Bar类,并且将其作为FooTest类中的单独方法进行定义,并且在尝试使用该类之前,都无法定义该类。 我收到一个NameError异常。 我是否被迫在每个测试方法中定义Bar类,或者我缺少什么? Bar类应该是一个测试装置。 我不打算在测试之外使用它,但是它确实演示了Foo父类的具体功能。 我的示例是人为的并且过于简化,但是我的意思是,我不想为Bar类定义一个单独的类文件,因为它仅用于测试。

如果我在FooTest类定义中定义了Bar类,这行得通吗? Python在Java中是否具有等效的内部类?

这让我想起了PHPUnit的模拟对象。 我相信unittest模块不支持它们,但是也许有些插件可以为您提供此功能,这肯定比滚动您自己的解决方案更好,我会首先尝试找到这种插件。

无论如何,Python是非常通用的,尤其是它的类也是对象! 因此,您可以执行以下操作:

class FooTest(unittest.TestCase):
    def setUp(self):
        class Bar(Foo):
            def defineStuff(stuff):
                self.stuff = stuff
                return self
        # store class locally
        self.Bar = Bar

    def testDefineStuff(self):
        bar = self.Bar().defineStuff('abcdefg')
        self.assertEquals('abcdefg', bar.stuff)

关于您有关嵌套类的问题,我不知道,只需尝试一下即可。 请记住,尽管其他几种语言的隐式作用域(即在this为可选)不是Python的功能/故障之一,所以您始终必须将嵌套类称为self.BarFooTest.Bar

我解释了昨晚我所做的相当糟糕的尝试(在凌晨4点发布问题可能不是最明智的想法)。 考虑到我的示例出现的方式,这些评论是有效的。

下面的Foo类比我的原始示例简单一些:

class Foo:
  def __init__(self):
    self.stuff = self.defineStuff()

  def defineStuff(self):
    return []

  def doStuff(self):
    try:
      return [x + x for x in self.stuff]
    except TypeError:
      raise FooException("defineStuff must return a list")

class FooTest(unittest.TestCase):
  def testDoStuff(self):
    v = Foo().doStuff()
    self.assertEquals([], v)

因此,这里的defineStuff方法没有存根,而是返回它可以的最基本值,因为该类是要扩展的。 现在实际上测试doStuff甚至defineStuff确实有意义,因为这两种方法实际上都已实现。

回到我试图问与我原来的问题...正如我在评论中提到的,我不打算给这个项目的范围内定义子类。 (我确实打算在其他项目中这样做,但是我想知道该项目在继续之前会按预期工作。)因此,即使使用实际值定义了defineStuff ,我仍然不知道如果更复杂的情况会起作用。

如果子类将defineStuff定义为返回[[1,2], [3,4], [5,6]] defineStuff [[1,2], [3,4], [5,6]]怎么办? 我是否知道这可以正常工作并返回[[1, 2, 1, 2], [3, 4, 3, 4], [5, 6, 5, 6]] 从理论上讲,应该。 这个例子特别简单,我可以看一下并知道它会。 但是我还没有对它进行确定的测试,并且我不想定义一个单独的子类来这样做,因为我永远不会使用它。

关于是否可以在unittest.TestCase派生的类的setUp方法中定义类并让其被您的测试方法识别的问题,尚无定论。 但是,我意识到我可以按照以下方式进行操作:

class FooTest(unittest.TestCase):
  @staticmethod
  def sampleStuff(placeholder):
    return [[1, 2], [3, 4], [5, 6]]

  def testDoStuff(self):
    Foo.defineStuff = FooTest.sampleStuff
    v = Foo().doStuff()
    self.assertEquals([[1, 2, 1, 2], [3, 4, 3, 4], [5, 6, 5, 6]], v)

因此,通过这种方式,我不需要定义一次性测试类来进行测试,但是我可以至少涵盖客户端可以定义defineStuff的可能方式的子集。 我将无法涵盖所有​​内容,而且我也不打算这样做,但是我可以做的测试用例越多,我就至少可以肯定地确定我的逻辑能够按预期工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM