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

Pharo中自动生成测试方法的参数集成问题求助

自动生成测试方法的参数集成问题

问题背景

要实现一个writeTestMethod:with:方法,输入原方法和一组初始化值,生成包含断言的测试方法:

  • 从原方法获取所属类,用默认构造初始化一个实例
  • 用传入值初始化同类型的另一个实例
  • 断言两个实例相等

已有buildSelectorFor:方法生成测试方法名(如buildSelectorFor:Car>>#speed:mark:返回testSpeedMark),但当前实现的writeTestMethod:with:无法正确将参数集成到生成的测试代码中。

现有代码

生成测试方法名的方法

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

存在问题的writeTestMethod:with:

writeTestMethod: aMethod with: anObject 
    ^(self buildTestSelectorFor: aMethod),'
      |classMethod setter instObject method|
      classMethod := aMethod methodClass.
    setter := (classMethod  allSelectorsInProtocol: #setter) asArray.
    instObject := classMethod new.
    (setter with: anObject do: [:set :ivar | instObject  perform: set with: ivar]).
     self assert: instObject class equals: (classMethod new) class.'

问题原因

当前代码直接在生成的测试代码中引用aMethod、anObject等外部变量,但生成的测试方法是独立的代码块,无法访问这些外部参数,必须将参数的具体值嵌入到生成的代码字符串中。

解决方案

修改writeTestMethod:with:方法,将参数转换为静态代码内容嵌入,同时修正断言逻辑(原断言仅判断类相等,无实际意义):

writeTestMethod: aMethod with: anObject
    | testSelector className setters |
    testSelector := self buildSelectorFor: aMethod.
    className := aMethod methodClass name.
    "从原方法的关键字提取对应的setter(如speed:mark:对应#speed:、#mark:)"
    setters := aMethod selector keywords collect: [:kw | kw asSymbol].

    ^ String streamContents: [:stream |
        "写入测试方法名"
        stream << testSelector << String cr.
        "声明临时变量"
        stream << '    | instanceWithValues defaultInstance |' << String cr.
        "初始化用传入值配置的实例"
        stream << '    instanceWithValues := ' << className << ' new.' << String cr.
        setters with: anObject do: [:setter :value |
            stream << '    instanceWithValues ' << setter << ' ' << value printString << '.' << String cr].
        "初始化默认实例"
        stream << '    defaultInstance := ' << className << ' new.' << String cr.
        "断言两个实例相等(需目标类实现=和hash方法)"
        stream << '    self assert: instanceWithValues equals: defaultInstance.' << String cr]

关键改进

  1. 静态值嵌入:将类名、初始化值直接转换为字符串写入生成的代码,避免引用外部变量。
  2. 显式setter调用:生成直观的setter调用代码(如instanceWithValues speed: 100.),替代动态perform:,提升测试代码可读性。
  3. 修正断言逻辑:改为断言实例相等,符合测试需求(需确保目标类正确实现=和hash方法,否则需调整断言逻辑为逐个属性验证)。

示例输出

调用writeTestMethod: Car>>#speed:mark: with: #(120 'B')将生成:

testSpeedMark
    | instanceWithValues defaultInstance |
    instanceWithValues := Car new.
    instanceWithValues speed: 120.
    instanceWithValues mark: 'B'.
    defaultInstance := Car new.
    self assert: instanceWithValues equals: defaultInstance.

内容的提问来源于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 08:05:29