2009年8月20日 星期四

單元測試(1): 什麼是單元測試

什麼是單元測試呢?在 Visual Studio 2008 上,在 method 上很簡單,按個右鍵,就可以建立一個單元測試了。如下圖。
image

但是,接下來寫的,就一定是「單元」測試嗎?

類似的問題也發生在物件導向語上。「使用c# 語言開發的程式,一定符合物件導向的程式碼嗎?」

使用c#來寫程式,也需要有物件導向的精神,才能寫出物件導向的程式。這是人為的。
使用Create Unit Tests 的工具來建立單元測試,也必須讓我們寫的測試符合「單元」的精神,才是真的單元測試。

定義

  1. A unit test is a piece of a code (usually a method) that invokes another piece of code and checks the correctness of some assumptions afterward.
  2. If the assumptions turn out to be wrong, the unit test has failed.
  3. A “unit” is a method or function

注意到第3點,unit 所指的測試範圍是一個 method 及 function 的程式碼。

舉例來說,以下的程式碼可以做單元測試,因為沒有涉及其他的程式碼

 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ClassLibrary1
{
  public class MyMath
  {
    public int Add(int a, int b)
    {
      return b + a;
    }
  }
}

但下面的程式碼就不容易做單元測試。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Configuration;
using Microsoft.Practices.Unity;

namespace ClassLibrary1
{
  public class Project
  {
    private ISettings _settings;
    IAuthenticationService _authenticationService;
    public Project(ISettings settings, IAuthenticationService authenticationService)
    {
      this._settings = settings;
      this._authenticationService = authenticationService;
    }

    [Dependency]
    public IWriteLog Logger { get; set; }

    public float GetProjectActualHours(int vProjId, string userName, string pwd)
    {
      if (!_authenticationService.Authenticate(userName, pwd))
      {
        Logger.WriteLog("xxx ");
        throw new NotFiniteNumberException();
      }

      string xmlPath = _settings.XmlPath;
      XElement el = XElement.Load(xmlPath);

      var projectNode = (from e in el.Elements("project")
                         where (int)e.Attribute("ID") == vProjId
                         select e).FirstOrDefault();

      if (projectNode != null)
      {
        var q = (from e in projectNode.Elements("rec")
                 select (float)e.Attribute("Hours")).Sum();
        return q;
      }
      else
      {
        string message = "hello, no projId = " + vProjId;
        return 0;
      }
    }
  }
}

原因呢?當我們在進行GetProjectActualHours 的單元測試時,如果所呼叫的_authenticationService.Authenticate 方法失敗時,應該屬於GetProjectActualHours方法的測試失敗,還是_authenticationService.Authenticate的失敗?

因此,當測試的對象引用到別的程式時,就不容易進行單元測試了。

但是,無論如何,還是可以進行測試。只是,此時的測試不再是「單元」測試了,而是「整合」測試,整合其他的服務/元件進行「整合測試」。或者,「元件測試」的名詞較容易為大家接受

請繼續讀 單元測試(2): 單元測試的好與壞

沒有留言:

Share with Facebook