2

我想以onlyGenerateCoverageForSpecifiedTargets编程方式将属性添加到 TestAction 对象。根据文档,此属性尚不受支持。所以我需要给一个对象添加一个自定义属性。我还需要添加CodeCoverageTargets组。这是我的代码:

scheme = Xcodeproj::XCScheme.new
scheme.add_build_target(app_target)
scheme.set_launch_target(app_target)
scheme.add_test_target(target)

test_action = scheme.test_action
test_action.code_coverage_enabled = true

# add onlyGenerateCoverageForSpecifiedTargets = true

scheme.test_action = test_action
scheme.save_as(xcode_proj_dir, name)

这是我从 Xcode GUI 添加属性时的 xml 结构。

   <TestAction
      buildConfiguration = "Debug"
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      shouldUseLaunchSchemeArgsEnv = "YES"
      codeCoverageEnabled = "YES"
      onlyGenerateCoverageForSpecifiedTargets = "YES">
      <MacroExpansion>
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "D7CE66BC1C7DE6F700FC64CC"
            BuildableName = "AppName.app"
            BlueprintName = "AppName"
            ReferencedContainer = "container:buddyui.xcodeproj">
         </BuildableReference>
      </MacroExpansion>
      <CodeCoverageTargets>
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "D7CE66BC1C7DE6F700FC64CC"
            BuildableName = "AppName.app"
            BlueprintName = "AppName"
            ReferencedContainer = "container:buddyui.xcodeproj">
         </BuildableReference>
      </CodeCoverageTargets>
4

2 回答 2

1

我先说:我对 Xcodeproj Gem 和 Xcode 元数据背后的逻辑一无所知。将我的代码作为进一步改进的起点。

您有几种方法可以实现您的要求:

  1. MonkeyPatch Xcodeproj。这就是我所做的,对此感到抱歉:-P

  2. 扩展 Xcodeproj 类。那将是推荐的解决方案。

  3. 使用 REXML 直接操作 XML 文件或 XCScheme 对象。

我的提议来了。我添加了一些方法TestAction(基于类似现有方法的代码)并创建了附加类CodeCoverageTargets(基于 class MacroExpansion)。由于我不知道 Xcode 是如何工作的,所以我选择创建方法add_code_coverage_targetsXCScheme不是覆盖set_launch_target(在哪里MacroExpansion实例化)。

require 'xcodeproj'

class Xcodeproj::XCScheme

  def add_code_coverage_targets(build_target)
    code_cov_targets = CodeCoverageTargets.new(build_target)
    test_action.add_code_coverage_targets(code_cov_targets)
  end

  class CodeCoverageTargets < XMLElementWrapper
    def initialize(target_or_node = nil)
      create_xml_element_with_fallback(target_or_node, 'CodeCoverageTargets') do
        self.buildable_reference = BuildableReference.new(target_or_node) if target_or_node
      end
    end
    def buildable_reference
      @buildable_reference ||= BuildableReference.new @xml_element.elements['BuildableReference']
    end
    def buildable_reference=(ref)
      @xml_element.delete_element('BuildableReference')
      @xml_element.add_element(ref.xml_element)
      @buildable_reference = ref
    end
  end

  class TestAction
    def only_generate_coverage_for_specified_targets?
      string_to_bool(@xml_element.attributes['onlyGenerateCoverageForSpecifiedTargets'])
    end
    def only_generate_coverage_for_specified_targets=(flag)
      @xml_element.attributes['onlyGenerateCoverageForSpecifiedTargets'] = bool_to_string(flag)
    end
    def code_coverage_targets
      @xml_element.get_elements('CodeCoverageTargets').map do |node|
        CodeCoverageTargets.new(node)
      end
    end
    def add_code_coverage_targets(code_coverage_targets)
      @xml_element.add_element(code_coverage_targets.xml_element)
    end

  end
end

你可以像这样使用它:

xcode_proj_dir = 'Desktop/SO/66719313/DummyApp.xcodeproj'
xcode_proj = Xcodeproj::Project.open(xcode_proj_dir)
app_target = xcode_proj.targets.first

scheme = Xcodeproj::XCScheme.new
scheme.add_build_target(app_target)
scheme.set_launch_target(app_target)
#scheme.add_test_target(app_target)
scheme.add_code_coverage_targets(app_target) # new method

test_action = scheme.test_action
test_action.code_coverage_enabled = true
test_action.only_generate_coverage_for_specified_targets = true # new method
puts test_action
于 2021-03-23T18:44:09.907 回答
0

您可以简单地创建一个模块来添加您想要的行为(即您的方法),但我不确定这会解决您的真正问题

module AddOnlyGenerateCoverageForSpecifiedTargets
  attr_accessor :only_generate_coverage_for_specified_targets 
end

然后将该模块包含在您想要的类中。要将其仅包含在一个对象中,请将其包含在其 singleton_class 中:

test_action.singleton_class.include AddOnlyGenerateCoverageForSpecifiedTargets

# Now you can use it
test_action.only_generate_coverage_for_specified_targets = true
于 2021-03-20T10:29:09.647 回答