{
    "componentChunkName": "component---src-templates-blog-post-jsx",
    "path": "/post/how-to-parse-of-coverage-report-with-phpunit/",
    "result": {"data":{"site":{"siteMetadata":{"title":"WEB EGG","author":"Leko - CTO at Yuimedi"}},"markdownRemark":{"id":"9b587a68-6e13-5278-ac1a-70405af60857","excerpt":"こんにちは。 仕事の方でテストカバレッジをGUIなしに集計する必要が出たので、 メソッド単位のカバレッジを集計したい クラス単位でのカバレッジを集計したい ファイル単位でのカバレッジを集計したい ディレクトリ単位でのカバレッジを集計したい の集計をするために、PHPUnitが出力するClover形式のXML…","html":"<p>こんにちは。<br>\n仕事の方でテストカバレッジをGUIなしに集計する必要が出たので、</p>\n<ul>\n<li>メソッド単位のカバレッジを集計したい</li>\n<li>クラス単位でのカバレッジを集計したい</li>\n<li>ファイル単位でのカバレッジを集計したい</li>\n<li>ディレクトリ単位でのカバレッジを集計したい</li>\n</ul>\n<p>の集計をするために、PHPUnitが出力するClover形式のXMLと格闘して得られた、XMLの構造と扱い方についてまとめてみました</p>\n<!--more-->\n<h2 id=\"はじめに\" style=\"position:relative;\"><a href=\"#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB\" aria-label=\"はじめに permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>はじめに</h2>\n<p>レガシーなPHPと戦っており、PHPUnitのバージョンは3.4です<br>\n<strong>最高につらい</strong></p>\n<p>なので出力されるXMLの構造や属性名に差異があるかもしれません<br>\nまた、カバレッジレポートの出力方法は<a href=\"https://phpunit.de/manual/3.4/ja/index.html\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">こちらのドキュメント</a>を参照して下さい</p>\n<p>なお、PHPUnitのカバレッジレポート単体ではC0のカバレッジしか計測できませんでした<br>\n後述するlineタグのnum属性とcount属性の値を使って対象プログラムの静的解析かければ、解析できなくはないかもしれませんが、<br>\nカバレッジレポート単体ではC0のレポートしか出ません。</p>\n<h2 id=\"カバレッジxmlの書式\" style=\"position:relative;\"><a href=\"#%E3%82%AB%E3%83%90%E3%83%AC%E3%83%83%E3%82%B8xml%E3%81%AE%E6%9B%B8%E5%BC%8F\" aria-label=\"カバレッジxmlの書式 permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>カバレッジXMLの書式</h2>\n<p>この当時のPHPUnitには<code>--coverage-clover</code>というオプションがあります<br>\nこれがXML形式のカバレッジレポートを出力してくれるオプションです</p>\n<h2 id=\"カバレッジレポートxmlの基本的な構造\" style=\"position:relative;\"><a href=\"#%E3%82%AB%E3%83%90%E3%83%AC%E3%83%83%E3%82%B8%E3%83%AC%E3%83%9D%E3%83%BC%E3%83%88xml%E3%81%AE%E5%9F%BA%E6%9C%AC%E7%9A%84%E3%81%AA%E6%A7%8B%E9%80%A0\" aria-label=\"カバレッジレポートxmlの基本的な構造 permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>カバレッジレポート(XML)の基本的な構造</h2>\n<p>XMLはざっくり、こんな感じになりました</p>\n<div class=\"gatsby-highlight\" data-language=\"html\"><pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>coverage</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>project</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>file</span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>ファイルパス<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>\n      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>class</span>\n        <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>クラス名<span class=\"token punctuation\">\"</span></span>\n        <span class=\"token attr-name\">namespace</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>名前空間<span class=\"token punctuation\">\"</span></span>\n      <span class=\"token punctuation\">></span></span>\n        <span class=\"token comment\">&lt;!-- クラス単位でのメトリクス --></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>metrics</span>\n          <span class=\"token attr-name\">methods</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>クラス内のメソッド数<span class=\"token punctuation\">\"</span></span>\n          <span class=\"token attr-name\">coveredmethods</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>カバレッジ100%のメソッド数<span class=\"token punctuation\">\"</span></span>\n          <span class=\"token attr-name\">statements</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>クラス内の有効行数<span class=\"token punctuation\">\"</span></span>\n          <span class=\"token attr-name\">coveredstatements</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>クラス内の行カバーしている有効行数<span class=\"token punctuation\">\"</span></span>\n        <span class=\"token punctuation\">/></span></span>\n      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>class</span><span class=\"token punctuation\">></span></span>\n\n<span class=\"token comment\">&lt;!-- ファイル内に定義されているクラスの分だけ上記繰り返し --></span>\n      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>line</span>\n        <span class=\"token attr-name\">num</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>左記メソッドの定義開始行<span class=\"token punctuation\">\"</span></span>\n        <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>method<span class=\"token punctuation\">\"</span></span>\n        <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>メソッド名<span class=\"token punctuation\">\"</span></span>\n        <span class=\"token attr-name\">count</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>テストでこの行を通過した回数<span class=\"token punctuation\">\"</span></span>\n      <span class=\"token punctuation\">/></span></span>\n      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>line</span>\n        <span class=\"token attr-name\">num</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>行番号<span class=\"token punctuation\">\"</span></span>\n        <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>stmt<span class=\"token punctuation\">\"</span></span>\n        <span class=\"token attr-name\">count</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>テストでこの行を通過した回数<span class=\"token punctuation\">\"</span></span>\n      <span class=\"token punctuation\">/></span></span>\n\n<span class=\"token comment\">&lt;!-- メソッド定義のたびに type=\"method\" name=\"...\"が出現。それ以外は type=\"stmt\" --></span>\n\n<span class=\"token comment\">&lt;!-- ファイル単位でのメトリクス --></span>\n      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>metrics</span>\n        <span class=\"token attr-name\">loc</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>ファイル内の有効行数<span class=\"token punctuation\">\"</span></span>\n        <span class=\"token attr-name\">ncloc</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>カバーされていない有効行数<span class=\"token punctuation\">\"</span></span>\n        <span class=\"token attr-name\">classes</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>ファイル内のクラス数<span class=\"token punctuation\">\"</span></span>\n        <span class=\"token attr-name\">methods</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>ファイル内のメソッド数<span class=\"token punctuation\">\"</span></span>\n        <span class=\"token attr-name\">coveredmethods</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>ファイル内の100%カバーされているメソッド数<span class=\"token punctuation\">\"</span></span>\n        <span class=\"token attr-name\">statements</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>ファイル内の定義行を除いた有効行数<span class=\"token punctuation\">\"</span></span>\n        <span class=\"token attr-name\">coveredstatements</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>行カバーされているファイル内の定義行を除いた有効行数<span class=\"token punctuation\">\"</span></span>\n      <span class=\"token punctuation\">/></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>file</span><span class=\"token punctuation\">></span></span>  \n\n<span class=\"token comment\">&lt;!-- 対象カバレッジのメトリクス総まとめ --></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>metrics</span>\n      <span class=\"token attr-name\">files</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>カバレッジ集計対象のファイル数<span class=\"token punctuation\">\"</span></span>\n      <span class=\"token attr-name\">loc</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>カバレッジ集計対象の有効行数<span class=\"token punctuation\">\"</span></span>\n      <span class=\"token attr-name\">ncloc</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>カバレッジ集計対象のうちカバーされていない行数<span class=\"token punctuation\">\"</span></span>\n      <span class=\"token attr-name\">classes</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>カバレッジ集計対象のクラス数<span class=\"token punctuation\">\"</span></span>\n      <span class=\"token attr-name\">methods</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>カバレッジ集計対象のメソッド数<span class=\"token punctuation\">\"</span></span>\n      <span class=\"token attr-name\">coveredmethods</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>カバレッジ集計対象のうち100%カバーされているメソッド数<span class=\"token punctuation\">\"</span></span>\n      <span class=\"token attr-name\">statements</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>カバレッジ集計対象の有効行数（定義行を除く）<span class=\"token punctuation\">\"</span></span>\n      <span class=\"token attr-name\">coveredstatements</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>カバレッジ集計対象のカバーされている有効行数（定義行を除く）<span class=\"token punctuation\">\"</span></span>\n    <span class=\"token punctuation\">/></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>project</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>coverage</span><span class=\"token punctuation\">></span></span></code></pre></div>\n<p><code>有効行数</code>は、空白行やコメントアウトなどを除いた、PHPのコードとして評価される行数を指しています。</p>\n<h2 id=\"クラス単位で行カバレッジを取る\" style=\"position:relative;\"><a href=\"#%E3%82%AF%E3%83%A9%E3%82%B9%E5%8D%98%E4%BD%8D%E3%81%A7%E8%A1%8C%E3%82%AB%E3%83%90%E3%83%AC%E3%83%83%E3%82%B8%E3%82%92%E5%8F%96%E3%82%8B\" aria-label=\"クラス単位で行カバレッジを取る permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>クラス単位で行カバレッジを取る</h2>\n<p>jsで書くと、</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> el <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">querySelector</span><span class=\"token punctuation\">(</span><span class=\"token string\">'class[name=\"クラス名\"][namespace=\"名前空間\"]>metrics'</span><span class=\"token punctuation\">)</span>\nconsole<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">.</span>coveredstatements <span class=\"token operator\">/</span> el<span class=\"token punctuation\">.</span>statements<span class=\"token punctuation\">)</span></code></pre></div>\n<p>に相当します</p>\n<p>classタグ1つにつきmetricsタグが1つはいっているので、<br>\n目的のクラスの中にあるmetricsタグを抽出し、有効行数とカバーしている有効行数で比較できます。</p>\n<p>namespaceを入れないと衝突する恐れがあります。<br>\nもしその辺考慮しなくていいならnamespace属性は無視できます。</p>\n<h2 id=\"ファイル単位で行カバレッジを取る\" style=\"position:relative;\"><a href=\"#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E5%8D%98%E4%BD%8D%E3%81%A7%E8%A1%8C%E3%82%AB%E3%83%90%E3%83%AC%E3%83%83%E3%82%B8%E3%82%92%E5%8F%96%E3%82%8B\" aria-label=\"ファイル単位で行カバレッジを取る permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>ファイル単位で行カバレッジを取る</h2>\n<p>ファイルも同じ要領で、fileタグ1つの直下にmetricsタグが1つ入っているので、それを比較します。</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> el <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">querySelector</span><span class=\"token punctuation\">(</span><span class=\"token string\">'file[name=\"ファイルパス\"]>metrics'</span><span class=\"token punctuation\">)</span>\nconsole<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">.</span>coveredstatements <span class=\"token operator\">/</span> el<span class=\"token punctuation\">.</span>statements<span class=\"token punctuation\">)</span></code></pre></div>\n<p>ファイル名（<a href=\"php.net/manual/ja/function.basename.php\">basepath</a>相当）ではなく、フルパスな点に注意です。<br>\nテストを実行（カバレッジ集計）した環境によって変わるのでご注意下さい。</p>\n<h2 id=\"ディレクトリ単位でカバレッジを取る\" style=\"position:relative;\"><a href=\"#%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E5%8D%98%E4%BD%8D%E3%81%A7%E3%82%AB%E3%83%90%E3%83%AC%E3%83%83%E3%82%B8%E3%82%92%E5%8F%96%E3%82%8B\" aria-label=\"ディレクトリ単位でカバレッジを取る permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>ディレクトリ単位でカバレッジを取る</h2>\n<p>カバレッジレポートはfileタグ単位で纏まっているので、ディレクトリごとのカバレッジを完璧に取ることは困難です。<br>\n<strong>もしソースの実体があれば</strong> ディレクトリの中身を漁って有効行数を出すことが可能ですが、<br>\nソースの実体を持たない限り、カバレッジレポートに記載されているファイルしか計測対象になりません。</p>\n<p>その不完全な状態であれば、</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> metricses <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">querySelectorAll</span><span class=\"token punctuation\">(</span><span class=\"token string\">'file[name^=\"ディレクトリまでのパス\"]>metrics'</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">const</span> dirMetrics <span class=\"token operator\">=</span> metricses<span class=\"token punctuation\">.</span><span class=\"token function\">reduce</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">acc<span class=\"token punctuation\">,</span> metrics</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  statements<span class=\"token operator\">:</span> acc<span class=\"token punctuation\">.</span>statements <span class=\"token operator\">+</span> metrics<span class=\"token punctuation\">.</span>statements<span class=\"token punctuation\">,</span>\n  coveredstatements<span class=\"token operator\">:</span> acc<span class=\"token punctuation\">.</span>coveredstatements <span class=\"token operator\">+</span> metrics<span class=\"token punctuation\">.</span>coveredstatements<span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> coveredstatements<span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span> statements<span class=\"token operator\">:</span> <span class=\"token number\">0</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\nconsole<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>dirMetrics<span class=\"token punctuation\">.</span>coveredstatements <span class=\"token operator\">/</span> dirMetrics<span class=\"token punctuation\">.</span>statements<span class=\"token punctuation\">)</span></code></pre></div>\n<p>相当で取得可能です。<br>\nディレクトリ内部のファイルのメトリクスをかき集めて、最後に合算すれば算出可能です</p>\n<h2 id=\"メソッド単位でカバレッジを取る\" style=\"position:relative;\"><a href=\"#%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E5%8D%98%E4%BD%8D%E3%81%A7%E3%82%AB%E3%83%90%E3%83%AC%E3%83%83%E3%82%B8%E3%82%92%E5%8F%96%E3%82%8B\" aria-label=\"メソッド単位でカバレッジを取る permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>メソッド単位でカバレッジを取る</h2>\n<p>※前置きでも話しましたが、バージョンアップによって改善されている可能性もあります。あくまで古いPHPUnitについて言及します。</p>\n<p>メソッド単位も、完全な情報は出せません<br>\nいや、正確にはメソッドに関するレポートなら出せます。が、関数に関するレポートが出せません しかも不完全な情報の収集ですら地味に面倒でした</p>\n<p>lineタグのtype属性は<code>stmt</code>か<code>method</code>にしかならず、関数の定義開始行は<code>type=stmt</code>になってしまいます<br>\n関数対して判別可能な値が何もありません。計測不可能です</p>\n<p>これもソースの実体があれば静的解析と絡めてレポート可能だとは思いますが、レポート単体では計測不可能でした<br>\nなので関数のレポートは出ないという前提で良ければ、</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> classes <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">querySelectorAll</span><span class=\"token punctuation\">(</span><span class=\"token string\">'file[name=\"探したいファイル\"]>class[]'</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">const</span> statementCounts <span class=\"token operator\">=</span> classes<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">cls</span> <span class=\"token operator\">=></span> <span class=\"token function\">parseInt</span><span class=\"token punctuation\">(</span>cls<span class=\"token punctuation\">.</span><span class=\"token function\">querySelector</span><span class=\"token punctuation\">(</span><span class=\"token string\">'metrics'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>statements<span class=\"token punctuation\">,</span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">const</span> lines <span class=\"token operator\">=</span> Array<span class=\"token punctuation\">.</span><span class=\"token function\">from</span><span class=\"token punctuation\">(</span>document<span class=\"token punctuation\">.</span><span class=\"token function\">querySelectorAll</span><span class=\"token punctuation\">(</span><span class=\"token string\">'file[name=\"探したいファイル\"]>line'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">let</span> currentClass <span class=\"token operator\">=</span> classes<span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>name\n<span class=\"token keyword\">let</span> currentMethod <span class=\"token operator\">=</span> <span class=\"token keyword\">null</span>\n<span class=\"token keyword\">let</span> currentStatements <span class=\"token operator\">=</span> <span class=\"token number\">0</span>\n<span class=\"token keyword\">let</span> metrics <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span>\nlines<span class=\"token punctuation\">.</span><span class=\"token function\">forEach</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">line</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>line<span class=\"token punctuation\">.</span>type <span class=\"token operator\">===</span> <span class=\"token string\">'method'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    currentMethod <span class=\"token operator\">=</span> line<span class=\"token punctuation\">.</span>name\n  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>line<span class=\"token punctuation\">.</span>type <span class=\"token operator\">===</span> <span class=\"token string\">'stmt'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>metrics<span class=\"token punctuation\">[</span>currentClass<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      metrics<span class=\"token punctuation\">[</span>currentClass<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>metrics<span class=\"token punctuation\">[</span>currentClass<span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span>currentMethod<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      metrics<span class=\"token punctuation\">[</span>currentClass<span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span>currentMethod<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span> statements<span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span> coveredStatements<span class=\"token operator\">:</span> <span class=\"token number\">0</span> <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token function\">parseInt</span><span class=\"token punctuation\">(</span>line<span class=\"token punctuation\">.</span>count<span class=\"token punctuation\">,</span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">></span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      metrics<span class=\"token punctuation\">[</span>currentClass<span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span>currentMethod<span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>coveredStatements <span class=\"token operator\">+=</span> <span class=\"token number\">1</span>\n    <span class=\"token punctuation\">}</span>\n    metrics<span class=\"token punctuation\">[</span>currentClass<span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span>currentMethod<span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>statements <span class=\"token operator\">+=</span> <span class=\"token number\">1</span>\n    currentStatements <span class=\"token operator\">+=</span> <span class=\"token number\">1</span>\n  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'知らないタイプ:'</span> <span class=\"token operator\">+</span> line<span class=\"token punctuation\">.</span>type<span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>currentStatements <span class=\"token operator\">===</span> <span class=\"token function\">parseInt</span><span class=\"token punctuation\">(</span>classes<span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>statements<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    classes<span class=\"token punctuation\">.</span><span class=\"token function\">shift</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    currentClass <span class=\"token operator\">=</span> classes<span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>name\n    currentStatements <span class=\"token operator\">=</span> <span class=\"token number\">0</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">const</span> methodMetrics <span class=\"token operator\">=</span> metrics<span class=\"token punctuation\">[</span>集計したいクラス<span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span>集計したいメソッド<span class=\"token punctuation\">]</span>\nconsole<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>methodMetrics<span class=\"token punctuation\">.</span>coveredStatements <span class=\"token operator\">/</span> methodMetrics<span class=\"token punctuation\">.</span>statements<span class=\"token punctuation\">)</span></code></pre></div>\n<p>ただし、これは不完全です<br>\n例えばクラスに属さない関数がファイルに含まれている場合に対応できません<br>\n完全なカバレッジを得るためにはソースコードと静的解析が必要です。</p>\n<p>PHPUnitの設定ファイルにて<a href=\"\">カバレッジ集計対象の設定</a>をして、<br>\nテストに登場しなかったファイルもカバレッジ集計対象に加えることは可能ですが、結局のところ関数には対応できません</p>\n<h2 id=\"まとめ\" style=\"position:relative;\"><a href=\"#%E3%81%BE%E3%81%A8%E3%82%81\" aria-label=\"まとめ permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>まとめ</h2>\n<ul>\n<li>行カバレッジの解析はXMLの構造さえ分かれば結構簡単\n<ul>\n<li>ファイル単位、クラス単位でのカバレッジなら確実に取れる</li>\n<li>関数が1つ以上定義されているファイルに対しては、ソースと突合しないとカバレッジ集計不可能</li>\n</ul>\n</li>\n<li>PHPには結構豊富なリフレクションのメソッドがあるので、突合は技術的には可能。今回は使ってない</li>\n</ul>\n<p>結果的な感想としては「ツラい」のただ一言でした。</p>","timeToRead":8,"frontmatter":{"title":"PHPUnitのカバレッジレポート(XML)を使ってカバレッジの計算してみた","tags":["PHP","PHPUnit"],"date":"May 09, 2017","featuredImage":null}}},"pageContext":{"slug":"/how-to-parse-of-coverage-report-with-phpunit/","previous":{"fields":{"slug":"/how-to-fix-access-denied-in-aws-athena/"},"frontmatter":{"title":"AWS Athenaでテーブルを作る時にAccess Deniedと怒られたら試すこと","tags":["AWS","AWS Athena"]}},"next":{"fields":{"slug":"/knowhow-of-circleci-1/"},"frontmatter":{"title":"CircleCI 1.0でDockerやdocker-composeを使用する際の制限と気をつけること","tags":["CI","CircleCI","Docker","Docker compose"]}}}},
    "staticQueryHashes": ["2585454260","2954598359"]}