将对象C从A类发送到B类

时间:2011-03-02 10:15:34

标签: python design-patterns class-design

我无法弄清楚如何在我的系统中设计类。

在classA中,我创建了对象selenium(它模拟了网站上的用户操作)。

在这个ClassA中,我创建了另一个对象,如SearchScreen,Payment_Screen和Summary_Screen。

# -*- coding: utf-8 -*-
from selenium import selenium
import unittest, time, re

class OurSiteTestCases(unittest.TestCase):
    def setUp(self):
        self.verificationErrors = []

        self.selenium = selenium("localhost", 5555, "*chrome", "http://www.someaddress.com/")
        time.sleep(5)
        self.selenium.start()        

    def test_buy_coffee(self):

        sel = self.selenium

        sel.open('/')
        sel.window_maximize()

        search_screen=SearchScreen(self.selenium)
        search_screen.choose('lavazza')

        payment_screen=PaymentScreen(self.selenium)
        payment_screen.fill_test_data()

        summary_screen=SummaryScreen(selenium)
        summary_screen.accept()


    def tearDown(self):
        self.selenium.stop()
        self.assertEqual([], self.verificationErrors)

if __name__ == "__main__":
    unittest.main()

这是SearchScreen模块的示例:

class SearchScreen:
    def __init__(self,selenium):
        self.selenium=selenium

    def search(self):
        self.selenium.click('css=button.search')

我想知道这些类的设计是否还有效?

3 个答案:

答案 0 :(得分:3)

如果SearchScreen / PaymentScreen / SummaryScreen只执行测试逻辑,那么我认为您可能只是将该逻辑放在OurSiteTestCases的实用方法中。

test_buy_coffee方法的可能设计(取决于您在SearchScreen等中的实际操作):

def test_buy_coffee(self):

    sel = self.selenium

    sel.open('/')
    sel.window_maximize()

    # Replace SearchScreen
    self.__choose_search()
    # Replace PaymentScreen
    self.__fill_payment_data()
    # Replace SummaryScreen
    self.__accept_summary()

修改 如果您需要将__choose_search,__ fill_payment_data和__accept_summary中的测试逻辑分解出来,以便在测试之间共享它,您可以在公共模块/包中编写相应的实用程序测试函数。或者,您可以编写包含selenium对象(self.selenium)的测试基类,并使用“protected”实用程序方法_choose_search,_fill_payment_data和_accept_summary。这一切都取决于你的案例中的实际情况:)

答案 1 :(得分:3)

你的方法很好。您有一组工具类,每个工具类都需要知道其目标。然后你有一个工具包类,可以在特定的目标上协调这些工具。

class AgreePrice:
    def __init__(self, connection): ...

class PlaceOrder:
    def __init__(self, connection): ...

class ConfirmAvailability:
    def __init__(self, connection): ...

class BookingService:
    def __init__(self, connection): ...

    def book(self): 
        for Command in (ConfirmAvailability, AgreePrice, PlaceOrder):
            command = Command(self.connection)
            command.run()
            assert command.success()

这些类结构没有任何问题,实际上它们总是出现,并且当单个“工具”类不能方便地放在一个函数中时,它们是一个相当好的设计。

如果你发现自己有一个有几十种方法的类,其中许多可以根据具体的任务进行分组,这是一个很好的重构。

作为一般规则,您希望确保您的“工具”类(SearchScreen等)在概念上低于您的控制器(您的测试用例)。它们适合你。

最简单的这些工具类是Function Object设计模式的一种形式。虽然在你的情况下,你在每个对象上调用的不仅仅是一个方法,所以它们更复杂一些。


或者,简而言之。你的设计很好,很常见。

答案 2 :(得分:1)

也许你可以使用责任链模式:

定义:     通过为多个对象提供处理请求的机会,避免将请求的发送者耦合到其接收者。链接接收对象并沿链传递请求,直到对象处理它。

示例在c#中:

  Handler h1 = new ConcreteHandler1();

  Handler h2 = new ConcreteHandler2();

  Handler h3 = new ConcreteHandler3();

  h1.SetSuccessor(h2);

  h2.SetSuccessor(h3);



  // Generate and process request

  int[] requests = { 2, 5, 14, 22, 18, 3, 27, 20 };


  foreach (int request in requests)
  {
    h1.HandleRequest(request);
  }

以下是完整的文档:http://www.dofactory.com/Patterns/PatternChain.aspx#_self1