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]
关键改进
- 静态值嵌入:将类名、初始化值直接转换为字符串写入生成的代码,避免引用外部变量。
- 显式setter调用:生成直观的setter调用代码(如
instanceWithValues speed: 100.),替代动态perform:,提升测试代码可读性。 - 修正断言逻辑:改为断言实例相等,符合测试需求(需确保目标类正确实现
=和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
相关产品推荐
相关产品推荐

