2010-12-04 149 views
1

问候,单元测试,黑盒测试时需要多长时间?

我遇到了一个奇怪的问题。

我相信测试代码时,你在参数X,Y,Z放到一个功能,你需要测试输出以保证工作正常进行。但是如果你的代码使用门面模式或者联系你可以查询的“内部”源代码,但是这很快就会在测试代码中引起紧耦合问题。

这里有一个例子:

class Notifier 

    def send_notification action_string 
    # contact messaging server and deliver message 
    end 

end 

class DoSpecialStuff 

    def my_method 
    code.. code.. 
    n = Notifier.new 
    n.send_notification "WOOT" 
    end 

end 

现在,DoSpecialStuff.my_method好好尝试一下有任何输出,但其目的是要输出去的地方抽象的“复杂性”的通知!从而导致无法测试的功能!

我们通过这样测试这段代码吗?现在

def test 
    assert_no_execption_raised do # hurm... a test in name only? 
    o = DoSpecialStuff.new 
    o.my_method 
    end 
end 

,我们可以检查,其中此消息去,但是从外观对象的点带走,我们试图隐藏的复杂性。

我们可以测试输出,但应该我们?什么是正确的?

-daniel

回答

2

它有助于始终牢记的是测试的关键在于可以帮助你,你的代码工作的信心,并将继续在今后的工作。

这看起来像那种地方互动的测试将是有益的。在DoSpecialStuff的测试中剔除通知程序,以确保它正确使用通告程序。越高,您可能需要嘲笑DoSpecialStuff来测试位于其上的代码。

+0

但是,当Mock' (urhm)对象,用比较少的“meta”语言(比如ruby),你必须通过通知者或从一些你可以控制的地方传入。这是因为通告程序对象是直接在类中创建的。这适用于红宝石(欢呼!),但什么是好的和一般的策略。 – Daniel 2010-12-04 01:03:53

0

,可能更符合你的情况的另一种方法是举实例,并在你的例子可能是方法调用,协作类的另一种方法是这样的:

class DoSpecialStuff 

    def my_method 
    code.. code.. 
    send_notification   
    end 

    def send_notifier 
    n = Notifier.new 
    n.send_notification "WOOT" 
    end 

end 

原谅我,如果我的语法错误,无论这是什么语言(Ruby?),我都不熟悉。

现在来测试,延长DoSpecialStuff覆盖send_notification,这样它要么什么也不做,或者你可以验证它被称为与测试(我假设有耀武扬威的全局变量的某种方式或类似)。

1

to allow your tests/code to scale neatly you should decouple your code using an interface,这使得重构简单得多,otherwise by coupling your code you incur technical debt你可能添加

  1. 接口来解耦代码
  2. 一个模拟的DoSpecialStuff测试的分离代码的行为像您期望
  3. 后更新测试

如果你在C++中编写代码,它看起来像

通告程序代码

Notifier.h 
class Notifier : public I_Notifier 
{ 
    void _sendNotification(NotificationInstance * notification); 
}; 

Notifier.cpp 
void Notifier::_sendNotification(NotificationInstance * notification) 
{ 
    //do some stuff that needs testing 
} 

接口的通知,这是被添加到DoSpecialStuff类解耦代码 I_Notifier.h

class I_Notifier 
{ 
    void sendNotification(NotificationInstance * notification) { _sendNotification(notification); } 
    virtual void _sendNotification(NotificationInstance * notification)=0; 
} 

模拟用于DoSpecialStuff的测试方面,我们的模拟假设通知程序代码工作我们的单元测试为DoSpecialStuff只是为了确保sendNotification被称为,所以我们的测试可以检查send_notification_called的状态,看看它是否成功o不是。

Mock_Notifier.h 
struct Test_Notifier : public I_Notifier 
{ 
    Test_Notifier() : send_notification_called(false) 

    virtual void _sendNotification(NotificationInstance * instance) 
    { 
    send_notification_called = true; 
    } 
    bool send_notification_called; 
}; 

DoSpecialStuff代码注意,此类现在已经到通知类这就是解耦代码的接口(因此我们的测试不再需要,除非我们使用从中调用包括实际的类

DoSpecialStuff.cpp 
class DoSpecialStuff 
{ 
    DoSpecialStuff(I_Notifier * n) : notifier_(n) {} 
    void DoSpecialStuff::_myMethod(NotificationInstance * notification) 
    I_Notifier * notifier_; 
} 

void DoSpecialStuff::_myMethod(NotificationInstance * notification) 
{ 
    //do some stuff that needs testing 
    n.send_notification (notification) 
} 

接口

I_DoSpecialStuff.h 
class I_DoSpecialStuff 
{ 
    void myMethod(NotificationInstance * notification) { _myMethod(notification); } 
    virtual void _myMethod(NotificationInstance * notification)=0; 
} 

凡功能是

  • 接触消息服务器和消息递送消息
上的单元测试顶部

你也有一组功能测试,所以单元测试将测试类的每一个方法(在适当情况下) ,功能测试套件将启动服务器的一个实例,然后功能测试将调用将与消息传递服务器联系的功能,然后检查输出(无论是数据库状态还是返回的信号)