簡體   English   中英

正則表達式,捕獲組和單元測試的良好設計

[英]Good Design For Regex, Capture Groups And Unit Testing

在一個項目中,我正在嘗試使用正則表達式來區分各種類型的句子,並將它們映射到處理這些句子的函數。

這些句子處理函數中的大多數都從句子本身獲取參數,由正則表達式中的捕獲組解析。

例如:“我為2個cookie支付了20美元”與我的解析樹(字典)中的一個正則表達式相匹配。 正則表達式將提取20美元作為組“價格”,將2作為組“金額”匹配。 目前我正在映射到正確的Handler函數並調用它如下:

foreach(KeyValuePair<Regex, Type> pair in sentenceTypes)
{
    Match match = pair.Key.Match(text);
    if(match.Success)
    {
        IHandler handler = handlerFactory.CreateHandler(pair.Value);
        output = handler.Handle(match);
    }
}

簡單處理程序類的示例。

public class NoteCookiePriceHandler
    {
        public string Handle(Match match)
        {
            double payment = Convert.ToDouble(match.Result("${payment}"));
            int amount = Convert.ToInt32(match.Result("${amount}"));

            double price = payment / amount;
            return "The price is $" + price;
        }
    }

我試圖用Moq設置一些單元測試來幫助,當我意識到我實際上不能模擬Match對象,也不是正則表達式。 考慮到這一點,設計似乎有些缺陷,因為我依賴於命名組被正確解析並傳遞給Handler類而沒有良好的接口。

我正在尋找有關更有效的設計的建議,用於正確地將參數傳遞給映射的處理函數/類,因為傳遞Match對象似乎有問題。

如果做不到這一點,任何幫助找出有效模擬正則表達式或匹配的方法都會受到贊賞,至少可以幫助我解決我的短期問題。 它們都缺少默認構造函數,因此我很難讓Moq創建它們的對象。

編輯:我最后通過為我的匹配組傳遞字符串字典而不是(不可Moq-able)匹配對象本身來解決至少模擬問題。 我對這個解決方案並不是特別滿意,所以建議仍然會受到贊賞。

foreach(KeyValuePair<Regex, Type> pair in sentenceTypes)
        {
            match = pair.Key.Match(text);
            if(match.Success)
            {
                IHandler handler= handlerFactory.CreateHandler(pair.Value);
                foreach (string groupName in pair.Key.GetGroupNames())
                {
                    matchGroups.Add(groupName, match.Groups[groupName].Value);
                }
                interpretation = handler.Handle(matchGroups);

避免糟糕設計的一種方法是從良好設計的原則開始,而不僅僅是您希望解決的問題。 這是測試驅動開發在轉換代碼質量方面如此強大的原因之一。 這種思維方式在TDD之前確實存在,但名稱為:按合同設計。 請允許我證明:

您希望理想的處理程序看起來像什么? 這個怎么樣:

interface IHandler {
    String handle();
}

執行:

public class NoteCookiePriceHandler : IHandler
{  
    private double payment;
    private int amount;

    public NoteCookiePriceHandler(double payment, int amount) {
        this.payment = payment;
        this.amount = amount;
    }

    public String handle() {
        return "The price is $" + payment / amount;
    }
}

現在從這個理想的設計開始,也許是對這個設計的測試。 如何才能將句子的句子輸入發送給處理程序? 那么,計算機科學中的所有問題都可以通過另一層間接解決。 假設句子解析器不直接創建處理程序,而是使用工廠創建一個:

interface HandlerFactory<T> where T: IHandler  {
    T getHandler(KeyValuePair<String, String> captureGroups);
}

然后,您可以為每個處理程序創建一個工廠,但很快您就會找到創建通用工廠的方法。 例如,使用反射可以將捕獲組名稱與構造函數參數進行匹配。 根據構造函數參數的數據類型,您可以自動讓通用處理程序工廠將字符串轉換為正確的數據類型。 通過創建一些假處理程序並要求工廠使用一些鍵值對字符串輸入填充它們,這一切都可以輕松測試。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM