You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pharo中如何基于源码生成带方法体的测试方法

问题分析

你的核心问题是未针对目标方法的参数列表生成关联测试逻辑,反而错误遍历#setter协议选择器,导致生成代码与目标方法脱节。以下是针对性修正方案:

核心解决思路

  1. 提取目标方法的参数元信息(数量、参数名)
  2. 将传入的测试参数值列表与方法参数一一绑定
  3. 生成包含变量声明、参数赋值、目标方法调用、断言语句的完整测试方法体

修改后的代码实现

buildSelectorFor: aMethod
    ^ String streamContents: [:stream || capitalize |
        capitalize := true.
        stream << 'test'.
        aMethod selector do: [:char |
            char = $:
                ifTrue: [ capitalize := true ]
                ifFalse: [ capitalize
                            ifTrue: [ 
                                capitalize := false.
                                stream << char asUppercase. ]
                            ifFalse:[ stream << char ]]]]

writeTestMethod: aMethod with: testArguments
    | paramNames selectorParts |
    paramNames := aMethod argumentNames.
    selectorParts := aMethod selector splitOn: $:.
    selectorParts := selectorParts allButLast. "移除拆分后末尾的空元素"
    
    ^ String streamContents: [:stream |
        "写入测试方法选择器"
        stream << (self buildSelectorFor: aMethod); cr.
        "写入方法体缩进"
        stream << '    '.
        "声明局部变量"
        stream << '| '.
        stream << 'testInstance '.
        paramNames do: [:name | stream << name, 'Value '].
        stream << '|'; cr.
        
        "初始化测试实例"
        stream << '    testInstance := ' << aMethod methodClass name << ' new.'; cr.
        
        "为每个参数赋值"
        paramNames withIndexDo: [:name :index |
            stream << '    ' << name, 'Value := ' << (testArguments at: index) asString << '.'; cr].
        
        "调用目标方法"
        stream << '    testInstance '.
        selectorParts withIndexDo: [:part :index |
            stream << part << ': ' << (paramNames at: index), 'Value '].
        stream << '.'; cr.
        
        "生成断言(假设setter对应同名无冒号的getter)"
        selectorParts withIndexDo: [:part :index |
            stream << '    self assert: testInstance ' << part << ' equals: ' << (paramNames at: index), 'Value.'; cr]]

执行示例

调用代码:

self writeTestMethod: Car>>#speed:mark: with: #(100 'A')

生成的测试代码:

testSpeedMark
    | testInstance speedValue markValue |
    testInstance := Car new.
    speedValue := 100.
    markValue := 'A'.
    testInstance speed: speedValue mark: markValue.
    self assert: testInstance speed equals: speedValue.
    self assert: testInstance mark equals: markValue.

关键细节说明

  • aMethod argumentNames:直接获取目标方法的参数名(如#speed:mark:对应#('speed' 'mark'))
  • selectorParts:将选择器按:拆分后清理无效元素,用于构建消息发送和断言语句
  • 使用String streamContents替代字符串拼接,避免格式混乱和缩进错误
  • 测试参数列表testArguments需与目标方法参数数量严格对应

内容的提问来源于stack exchange,提问作者Mansour Faouziel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 20:05:33