{"id":91852,"date":"2020-11-05T11:38:51","date_gmt":"2020-11-05T10:38:51","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=youtrack&#038;p=91852"},"modified":"2021-04-16T09:18:13","modified_gmt":"2021-04-16T08:18:13","slug":"optimieren-sie-ihren-workflow-teil-13-unterstuetzung-von-testverwaltungsszenarien","status":"publish","type":"youtrack","link":"https:\/\/blog.jetbrains.com\/de\/youtrack\/2020\/11\/optimieren-sie-ihren-workflow-teil-13-unterstuetzung-von-testverwaltungsszenarien\/","title":{"rendered":"Optimieren Sie Ihren Workflow \u2014 Teil 13: Unterst\u00fctzung von Testverwaltungsszenarien"},"content":{"rendered":"<p><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/11\/YT_workflow_de.png\" alt=\"\" \/><\/p>\n<p>Willkommen zur\u00fcck zu unserer Reihe \u201eOptimieren Sie Ihren Workflow\u201c! Wir wurden immer wieder von der Community aufgefordert, die YouTrack-Funktionen f\u00fcr QA-Teams zu thematisieren. Heute m\u00f6chten wir der Frage nachgehen, wie ein Testmanagement-Szenario (TMS) in YouTrack verwaltet werden kann. In diesem Artikel zeigen wir Ihnen, wie Sie YouTrack so einrichten k\u00f6nnen, dass die Testmanagement-Funktionalit\u00e4t innerhalb von YouTrack verwaltet werden kann, ganz ohne L\u00f6sungen von Drittanbietern. Mit diesem Ansatz sparen Sie Lizenzkosten und vereinfachen den Testverwaltungsprozess.<\/p>\n<p>Dieser Artikel richtet sich einerseits an Testverantwortliche \u2013 und andererseits an alle, die an YouTrack-Workflows interessiert sind. Wir zeigen Ihnen ein praktisches Beispiel zum Einrichten eines Testprozesses in YouTrack, mit Empfehlungen f\u00fcr Projekt- und Ticketeinstellungen, einer Beschreibung zum Implementieren von Testmanagement-Szenarien und weiteren Informationen.<\/p>\n<p><span id=\"more-77371\"><\/span><\/p>\n<p>Wir haben auch eine Reihe von einsatzfertigen Workflow-Codebl\u00f6cken zusammengestellt, mit denen Sie Testmanagementprozesse automatisieren k\u00f6nnen. Diese Codebl\u00f6cke erleichtern verschiedene Aufgaben: Testf\u00e4lle einem bestimmten Testlauf zuordnen, Testl\u00e4ufe klonen, Systemvorschl\u00e4ge f\u00fcr den n\u00e4chsten Test anzeigen usw.<br \/>\n<a name=\"ref1\"><\/a><\/p>\n<h2>Einstellungen f\u00fcr Testmanagement-Projekte in YouTrack<\/h2>\n<p>In der Regel ist es sinnvoll, Testmanagement-spezifische Tickettypen zu verwenden: Test Case (Testfall), Test Suite (Testsuite; eine Sammlung von Testf\u00e4llen), Test Run (Testlauf; eine Reihe von Testf\u00e4llen oder Testsuiten, die einem bestimmten Testzyklus zugewiesen sind) oder Test Case Execution (Testfallausf\u00fchrung; einem bestimmten Testlauf zugeordnet). Sie sollten die Tickettypen entsprechend den Anforderungen Ihres TMS-Projekts <a href=\"https:\/\/www.jetbrains.com\/help\/youtrack\/standalone\/Manage-Custom-Fields-Per-Project.html#add-custom-field-to-project\" target=\"_blank\" rel=\"noopener\">konfigurieren<\/a>. Es gibt drei Arten von <a href=\"https:\/\/www.jetbrains.com\/help\/youtrack\/standalone\/Link-Types.html\" target=\"_blank\" rel=\"noopener\">Ticket-Verkn\u00fcpfungen<\/a>, um Verbindungen zwischen Ihren Testmanagement-Aufgaben herzustellen und die Relevanz zu kennzeichnen:<\/p>\n<ul>\n<li>Der Standard-Linktyp zwischen \u00fcbergeordneten Aufgaben und Teilaufgaben ist f\u00fcr Beziehungen zwischen Testl\u00e4ufen und Testfallausf\u00fchrungen sowie Testsuiten und Testf\u00e4llen geeignet. <\/li>\n<li>Mit dem benutzerdefinierten Linktyp Execution (Ausf\u00fchrung) werden Beziehungen zwischen Testf\u00e4llen und Testfallausf\u00fchrungen verwaltet. <\/li>\n<li>Der benutzerdefinierte Linktyp Related Bug (zugeh\u00f6riger Fehler) verwaltet Beziehungen zwischen fehlgeschlagenen Tests und zugeordneten Fehlern.<\/li>\n<\/ul>\n<p>Die Testanforderungen k\u00f6nnen als <a href=\"https:\/\/www.jetbrains.com\/help\/youtrack\/standalone\/create-articles.html\" target=\"_blank\" rel=\"noopener\">Artikel<\/a> \u00fcber ein Textfeld mit den Tickets verkn\u00fcpft werden.<br \/>\nDar\u00fcber hinaus k\u00f6nnen Sie f\u00fcr Ihre Testmanagement-Aufgaben <a href=\"https:\/\/www.jetbrains.com\/help\/youtrack\/standalone\/Manage-Custom-Fields-Per-Project.html#add-custom-field-to-project\" target=\"_blank\" rel=\"noopener\">benutzerdefinierte Felder<\/a> einrichten, zum Beispiel <em>Testmodus<\/em>, <em>Kategorie<\/em>, <em>Testablauf<\/em> und <em>Anwendung<\/em>. Sie k\u00f6nnen f\u00fcr diese Felder vordefinierte Werte festlegen (z.\u00a0B. einen vordefinierten Teststatus). Mit <a href=\"https:\/\/www.jetbrains.com\/help\/youtrack\/standalone\/conditional-custom-fields.html\" target=\"_blank\" rel=\"noopener\">bedingten Feldern<\/a> k\u00f6nnen Sie Informationen speziell f\u00fcr einen Tickettyp anzeigen.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/TMS0_1.png\" alt=\"\" \/><\/p>\n<p>Die Tickettypen \u201eTest Case\u201c (Testfall) und \u201eTest Run\u201c (Testlauf) verf\u00fcgen \u00fcber verschiedene vordefinierte Felder, die Sie an Ihre Anforderungen anpassen k\u00f6nnen.<\/p>\n<h2>Einrichten von Testl\u00e4ufen und Testausf\u00fchrungen<\/h2>\n<p>Wenn wir beispielsweise eine bestimmte Produktversion testen m\u00f6chten, m\u00fcssen wir einen Testlauf erstellen und diesem relevante Testsuiten und Testf\u00e4lle zuweisen. Dazu gehen Sie folgenderma\u00dfen vor:<\/p>\n<ul>\n<li>Erstellen Sie ein Ticket mit dem Tickettyp \u201eTest Run\u201c (Testlauf). <\/li>\n<li>Use the \u2018Assigned test case and test suite\u2019 custom link type to link to the issue.<\/li>\n<li>Geben Sie im Popup-Fenster die Testf\u00e4lle an, die Sie in den Testlauf aufnehmen m\u00f6chten.<\/li>\n<\/ul>\n<p>Der Workflow \u201ePopulate Test Run\u201c (Testlauf f\u00fcllen) erspart Ihrem QS-Team Zeit und M\u00fche:<\/p>\n<ul>\n<li>Von allen ausgew\u00e4hlten Testsuiten und Testf\u00e4llen werden Kopien im System erstellt. Alle Tickets werden als Tickettyp \u201eTest Case Execution\u201c (Testfallausf\u00fchrung) angelegt. <\/li>\n<li>Der Linktyp \u201eExecution\u201c (Ausf\u00fchrung) verbindet Testfallausf\u00fchrungen mit ausgew\u00e4hlten Testf\u00e4llen.<\/li>\n<li>Neu erstellte Tickets werden mit dem Testlauf als \u00fcbergeordnetem Ticket sowie mit den zugeh\u00f6rigen Teilaufgaben verkn\u00fcpft.<\/li>\n<\/ul>\n<p>So funktioniert es im Detail:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/resources.jetbrains.com\/storage\/products\/blog\/wp-content\/uploads\/done1s720cut.gif\" alt=\"\" \/><\/p>\n<details>\n<summary>\n        Codeblock ausklappen<br \/>\n    <\/summary>\n<p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-title=\"\">\nvar entities = require(&#039;@jetbrains\/youtrack-scripting-api\/entities&#039;);\nvar workflow = require(&#039;@jetbrains\/youtrack-scripting-api\/workflow&#039;);\n\nexports.rule = entities.Issue.onChange({\n  title: &#039;Populate-test-run&#039;,\n  guard: function(ctx) {\n    var issue = ctx.issue;\n    return !issue.isChanged(&#039;project&#039;) &amp;&amp; issue.Type &amp;&amp; (issue.Type.name == ctx.Type.TestRun.name) &amp;&amp; issue.links[ctx.Execution.outward].added.isNotEmpty() &amp;&amp; issue.isReported;\n  },\n  action: function(ctx) {\n    var issue = ctx.issue;\n    var totalTestRuns = issue.links[ctx.Execution.outward].added.size;\n    issue.links[ctx.Execution.outward].added.forEach(function(TestCase) {\n      TestCase.links[ctx.Execution.inward].delete(issue);\n\n      var TestCaseRun = TestCase.copy();\n      TestCaseRun.Type = ctx.Type.TestExecution.name;\n      TestCaseRun.Status = ctx.Status.NoRun.name;\n      Object.keys(TestCaseRun.links).forEach(function(linkType) {\n       if (!TestCaseRun.links[linkType])\n        return;\n         TestCaseRun.links[linkType].clear();\n      });\n      TestCaseRun.summary = \"[TEST_CASE_EXECUTION\" + \"] [\" + TestCaseRun.summary + \"]\";\n\n      TestCaseRun.links[ctx.Subtask.inward].add(issue);\n      issue.links[ctx.Subtask.outward].add(TestCaseRun);\n      TestCaseRun.links[ctx.Execution.outward].add(TestCase);\n    });\n    issue.fields[&#039;Total number of test cases&#039;] = totalTestRuns;\n  },\n  requirements: {\n    Execution: {\n      type: entities.IssueLinkPrototype,\n      name: &#039;Execution&#039;,\n      inward: &#039;Execution&#039;,\n      outward: &#039;Assigned test case or test suite&#039;\n    },\n    Subtask: {\n      type: entities.IssueLinkPrototype,\n      name: &#039;Subtask&#039;,\n      inward: &#039;parent for&#039;,\n      outward: &#039;subtask of&#039;\n    },\n    Type: {\n      type: entities.EnumField.fieldType,\n      TestExecution: {\n        name: \"Test Case Execution\"\n      },\n      TestRun: {\n        name: \"Test Run\"\n      },\n      TestCase: {\n        name: \"Test Case\"\n      },\n      TestSuite: {\n        name: \"Test Suite\"\n      }\n    },\n    Total: {\n      type: entities.Field.integerType,\n      name: &#039;Total number of test cases&#039;\n    },\n    TotalFailed: {\n      type: entities.Field.integerType,\n      name: &#039;Number of failed test cases&#039;\n    },\n    TotalPassed: {\n      type: entities.Field.integerType,\n      name: &#039;Number of passed test cases&#039;\n    },\n    Status: {\n      type: entities.EnumField.fieldType,\n      InProgress: {\n        name: &#039;In Progress&#039;\n      },\n      Passed: {\n        name: &#039;Passed&#039;\n      },\n      Failed: {\n        name: &#039;Failed&#039;\n      },\n      NoRun: {\n        name: &#039;No Run&#039;\n      },\n    },\n  }\n});\n<\/pre>\n<p>\n<\/details>\n<h2>Pflege der Testaktivit\u00e4ten<\/h2>\n<p>Sobald die Testl\u00e4ufe vollst\u00e4ndig eingerichtet sind, kann mit dem Testen begonnen werden. Standardm\u00e4\u00dfig haben alle Tickets mit den Typen \u201eTest Case Execution\u201c (Testfallausf\u00fchrung) und \u201eTest Run\u201c (Testlauf) den Status \u201eNo Run\u201c (Keine Ausf\u00fchrung).<\/p>\n<h3>Zwischen Tests wechseln<\/h3>\n<p>Wenn Sie mit mehreren Tests arbeiten, haben Sie zwei M\u00f6glichkeiten, um von einem Test zum anderen zu wechseln:<\/p>\n<ol>\n<li>\u00c4ndern Sie in der Ticketliste den Teststatus manuell. <\/li>\n<li>\u00d6ffnen Sie einen Test und wechseln Sie zum n\u00e4chsten nicht abgeschlossenen Test. When you want to switch tests in this way, a helpful pop-up appears that suggests the next test to run.<br \/>\n    The following actions can be automated:<\/p>\n<ul>\n<li> \u00dcberpr\u00fcfen, ob es Tests gibt, die den Status \u201eNo Run\u201c haben und demselben Testlauf angeh\u00f6ren.<\/li>\n<li> Anzeigen einer Nachricht mit der URL des n\u00e4chsten verf\u00fcgbaren Tests (falls vorhanden).\n<p>    <a href=\"https:\/\/resources.jetbrains.com\/storage\/products\/blog\/wp-content\/uploads\/done3s720.gif\" rel=\"attachment wp-att-6366 noopener\" target=\"_blank\"><img decoding=\"async\" src=\"https:\/\/resources.jetbrains.com\/storage\/products\/blog\/wp-content\/uploads\/done3s720.gif\" alt=\"ApplyingCommandForSubsystem\"  \/><\/a><\/li>\n<\/ul>\n<p> Dies kann mit dem folgenden Code implementiert werden.<\/p>\n<details>\n<summary>\n        Codeblock ausklappen<br \/>\n    <\/summary>\n<p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-title=\"\">\n action: function(ctx) {\n  var issue = ctx.issue;\n  if (!issue.links[&#039;subtask of&#039;].isEmpty) {\n              var parent = issue.links[&#039;subtask of&#039;].first();\n              var TestRunList = parent.links[ctx.Subtask.outward];\n              var resultSet = null;\n              var isPassing = true;\n              TestRunList.forEach(function(v) {\n                if (v.Status.name == ctx.Status.Failed.name) {\n                  isPassing = false;\n                } else if ((v.Status.name == ctx.Status.InProgress.name) &amp;&amp; (v.id !== issue.id)) {\n                  resultSet = v;\n                }\n              });\n              if (resultSet) {\n                var otherIssueLink = &#039;<a href=\"&#039; + resultSet.url + &#039;\"> &#039; + resultSet.id + &#039;<\/a>&#039;;\n                var message = &#039;Switch to next open test in current Test Run&#039; + otherIssueLink + &#039;.&#039;;\n                workflow.message(message);\n    }\n}\n}\n<\/pre>\n<p>\n<\/details>\n<\/ol>\n<h2>Teststatus <\/h2>\n<p><a name=\"ref2\"><\/a><\/p>\n<p>Beim Wechsel von einem Test zu einem anderen k\u00f6nnen Sie entweder angeben, dass der Test bestanden wurde (\u201ePassed\u201c), oder Sie k\u00f6nnen den Teststatus in \u201eFailed\u201c \u00e4ndern (falls w\u00e4hrend der Ausf\u00fchrung des Testfalls ein Fehler aufgetreten ist). Gem\u00e4\u00df den <a href=\"#ref1\">YouTrack-Einstellungen<\/a>, die wir urspr\u00fcnglich f\u00fcr dieses Projekt konfiguriert haben, gibt es mehrere vordefinierte Statuswerte f\u00fcr einen Testlauf:<\/p>\n<ul>\n<li>Failing: Mindestens einer der zugeordneten Tests hat den Status \u201eNo run\u201c, und mindestens einer der zugeordneten Tests hat den Status \u201eFailed\u201c.<\/li>\n<li>Passing: Mindestens einer der zugeordneten Tests hat den Status \u201eNo run\u201c, und es gibt keine zugeordneten Tests mit dem Status \u201eFailed\u201c.<\/li>\n<li>Failed: Es gibt keine zugeordneten Tests mit dem Status \u201eNo Run\u201c, und mindestens einer der zugeordneten Tests hat den Status \u201eFailed\u201c.<\/li>\n<li>Passed: Es gibt keine zugeordneten Tests mit dem Status \u201eNo Run\u201c oder \u201eFailed\u201c.<\/li>\n<\/ul>\n<p><img decoding=\"async\" src=\"https:\/\/resources.jetbrains.com\/storage\/products\/blog\/wp-content\/uploads\/done2s720.gif\" alt=\"\" \/><\/p>\n<p>Mit diesen Statuswerten kann Ihr QA-Team den Testfortschritt w\u00e4hrend des gesamten Testzyklus \u00fcberwachen. Zu beachten ist dabei, dass der Testlaufstatus nur von den zugeh\u00f6rigen Tests abh\u00e4ngt und nicht manuell ge\u00e4ndert werden sollte. Die Bestimmung des Testlaufstatus wird mithilfe des Workflows <a href=\"https:\/\/www.jetbrains.com\/help\/youtrack\/standalone\/state-machine-per-issue-type.html#state-machine-per-issue-type2\" target=\"_blank\" rel=\"noopener\">Zustandsautomat nach Tickettyp<\/a> implementiert. Der Codeblock f\u00fcr Testwechsel ist ebenfalls in den Workflow integriert.<\/p>\n<details>\n<summary>\n        Codeblock ausklappen<br \/>\n    <\/summary>\n<p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-title=\"\">\n\nvar entities = require(&#039;@jetbrains\/youtrack-scripting-api\/entities&#039;);\nvar workflow = require(&#039;@jetbrains\/youtrack-scripting-api\/workflow&#039;);\n\nexports.rule = entities.Issue.stateMachine({\n  title: &#039;status-management&#039;,\n  stateFieldName: &#039;Status&#039;,\n  typeFieldName: &#039;Type&#039;,\n  defaultMachine: {\n    &#039;No Run&#039;: {\n      initial: true,\n      transitions: {\n        &#039;Failed&#039;: {\n          targetState: &#039;Failed&#039;,\n          action: function(ctx) {\n            var issue = ctx.issue;\n            if (!issue.links[&#039;subtask of&#039;].isEmpty) {\n              var parent = issue.links[&#039;subtask of&#039;].first();\n              var TestRunList = parent.links[ctx.Subtask.outward];\n              var resultSet = null;\n              var isPassing = true;\n              TestRunList.forEach(function(v) {\n                if (v.Status.name == ctx.Status.Failed.name) {\n                  isPassing = false;\n                } else if ((v.Status.name == ctx.Status.InProgress.name) &amp;&amp; (v.id !== issue.id)) {\n                  resultSet = v;\n                }\n              });\n              if (resultSet) {\n                var otherIssueLink = &#039;<a href=\"&#039; + resultSet.url + &#039;\"> &#039; + resultSet.id + &#039;<\/a>&#039;;\n                var message = &#039;Switch to next open test in current Test Run&#039; + otherIssueLink + &#039;.&#039;;\n                workflow.message(message);\n                \/\/ Updating Test Run Status \n                parent.fields[\"Status\"] = ctx.Status.Failing;\n              } else {\n                parent.fields[\"Status\"] = ctx.Status.Failed;\n              }\n            }\n          }\n        },\n        &#039;Passed&#039;: {\n          guard: function(ctx) {\n            var issue = ctx.issue;\n            return !issue.isChanged(&#039;project&#039;) &amp;&amp; !issue.becomesReported &amp;&amp; issue.isReported &amp;&amp; (issue.Type.name == ctx.Type.TestExecution.name);\n          },\n          targetState: &#039;Passed&#039;,\n          action: function(ctx) {\n            var issue = ctx.issue;\n            if (!issue.links[&#039;subtask of&#039;].isEmpty) {\n              var parent = issue.links[&#039;subtask of&#039;].first();\n              var TestRunList = parent.links[ctx.Subtask.outward];\n              var resultSet = null;\n              var isPassing = true;\n              TestRunList.forEach(function(v) {\n                if (v.Status.name == ctx.Status.Failed.name) {\n                  isPassing = false;\n                } else if ((v.Status.name == ctx.Status.InProgress.name) &amp;&amp; (v.id !== issue.id)) {\n                  resultSet = v;\n                }\n              });\n              if (resultSet) {\n                var otherIssueLink = &#039;<a href=\"&#039; + resultSet.url + &#039;\"> &#039; + resultSet.id + &#039;<\/a>&#039;;\n                var message = &#039;Switch to next open test in current Test Run&#039; + otherIssueLink + &#039;.&#039;;\n                workflow.message(message);\n                parent.fields[\"Status\"] = (isPassing) ? ctx.Status.Passing : ctx.Status.Failing;\n              } else {\n                parent.fields[\"Status\"] = (isPassing) ? ctx.Status.Passed : ctx.Status.Failed;\n              }\n            }\n          }\n        }\n      }\n    },\n    Passed: {\n      transitions: {\n        &#039;Failed&#039;: {\n          guard: function(ctx) {\n            var issue = ctx.issue;\n            return !issue.isChanged(&#039;project&#039;) &amp;&amp; !issue.becomesReported &amp;&amp; issue.isReported &amp;&amp; (issue.Type.name == ctx.Type.TestExecution.name);\n          },\n          targetState: &#039;Failed&#039;,\n          action: function(ctx) {\n            var issue = ctx.issue;\n            if (!issue.links[&#039;subtask of&#039;].isEmpty) {\n             var parent = issue.links[&#039;subtask of&#039;].first();\n              var TestRunList = parent.links[ctx.Subtask.outward];\n              var resultSet = null;\n              TestRunList.forEach(function(v) {\n                if (v.Status.name == ctx.Status.Failed.name) {\n                } else if ((v.Status.name == ctx.Status.InProgress.name) &amp;&amp; (v.id !== issue.id)) {\n                  resultSet = v;\n                }\n              });\n              if (resultSet) {\n                var otherIssueLink = &#039;<a href=\"&#039; + resultSet.url + &#039;\"> &#039; + resultSet.id + &#039;<\/a>&#039;;\n                var message = &#039;Switch to next open test in current Test Run&#039; + otherIssueLink + &#039;.&#039;;\n                workflow.message(message);\n                parent.fields[\"Status\"] = ctx.Status.Failing;\n              } else {\n                parent.Status = ctx.Status.Failed;\n              }\n            }\n          }\n        },\n        &#039;No Run&#039;: {\n          guard: function(ctx) {\n            var issue = ctx.issue;\n            return !issue.isChanged(&#039;project&#039;) &amp;&amp; !issue.becomesReported &amp;&amp; issue.isReported &amp;&amp; (issue.Type.name == ctx.Type.TestExecution.name);\n          },\n          targetState: &#039;No Run&#039;,\n          action: function(ctx) {\n            var issue = ctx.issue;\n            if (!issue.links[&#039;subtask of&#039;].isEmpty) {\n              var parent = issue.links[&#039;subtask of&#039;].first();\n              var TestRunList = parent.links[ctx.Subtask.outward];\n              var ActiveTestRun = false;\n              var isPassing = true;\n              TestRunList.forEach(function(v) {\n                if (v.Status.name == ctx.Status.Failed.name) {\n                  isPassing = false;\n                  ActiveTestRun = true;\n                } else if ((v.Status.name == ctx.Status.Passed.name) &amp;&amp; (v.id !== issue.id)) {\n                  ActiveTestRun = true;\n                }\n              });\n              if (ActiveTestRun) {\n                parent.fields[\"Status\"] = (isPassing) ? ctx.Status.Passing : ctx.Status.Failing;\n              } else parent.fields[\"Status\"] = ctx.Status.InProgress;\n            }\n          }\n        }\n      }\n    },\n    Failed: {\n      transitions: {\n        &#039;Passed&#039;: {\n          guard: function(ctx) {\n            var issue = ctx.issue;\n            return !issue.isChanged(&#039;project&#039;) &amp;&amp; !issue.becomesReported &amp;&amp; issue.isReported &amp;&amp; (issue.Type.name == ctx.Type.TestExecution.name);\n          },\n          targetState: &#039;Passed&#039;,\n          action: function(ctx) {\n            var issue = ctx.issue;\n            if (!issue.links[&#039;subtask of&#039;].isEmpty) {\n              var parent = issue.links[&#039;subtask of&#039;].first();\n              var TestRunList = parent.links[ctx.Subtask.outward];\n              var resultSet = null;\n              var isPassing = true;\n              TestRunList.forEach(function(v) {\n                if ((v.Status.name == ctx.Status.Failed.name) &amp;&amp; (v.id !== issue.id)) {\n                  isPassing = false;\n                } else if ((v.Status.name == ctx.Status.InProgress.name) &amp;&amp; (v.id !== issue.id)) {\n                  resultSet = v;\n                }\n              });\n              if (resultSet) {\n                var otherIssueLink = &#039;<a href=\"&#039; + resultSet.url + &#039;\"> &#039; + resultSet.id + &#039;<\/a>&#039;;\n                var message = &#039;Switch to next open test in current Test Run&#039; + otherIssueLink + &#039;.&#039;;\n                workflow.message(message);\n\n                parent.fields[\"Status\"] = (isPassing) ? ctx.Status.Passing : ctx.Status.Failing;\n              } else {\n                parent.fields[\"Status\"] = (isPassing) ? ctx.Status.Passed : ctx.Status.Failed;\n              }\n            }\n          }\n        },\n        &#039;No Run&#039;: {\n          guard: function(ctx) {\n            var issue = ctx.issue;\n            return !issue.isChanged(&#039;project&#039;) &amp;&amp; !issue.becomesReported &amp;&amp; issue.isReported &amp;&amp; (issue.Type.name == ctx.Type.TestExecution.name);\n          },\n          targetState: &#039;No Run&#039;,\n          action: function(ctx) {\n            var issue = ctx.issue;\n            if (!issue.links[&#039;subtask of&#039;].isEmpty) {\n              var parent = issue.links[&#039;subtask of&#039;].first();\n              var TestRunList = parent.links[ctx.Subtask.outward];\n              var ActiveTestRun = false;\n              var isPassing = true;\n              TestRunList.forEach(function(v) {\n                if ((v.Status.name == ctx.Status.Failed.name) &amp;&amp; (v.id !== issue.id)) {\n                  isPassing = false;\n                  ActiveTestRun = true;\n                } else if ((v.Status.name == ctx.Status.Passed.name) &amp;&amp; (v.id !== issue.id)) {\n                  ActiveTestRun = true;\n                }\n              });\n              if (ActiveTestRun) {\n                parent.fields[\"Status\"] = (isPassing) ? ctx.Status.Passing : ctx.Status.Failing;\n              } else parent.fields[\"Status\"] = ctx.Status.InProgress;\n            }\n          }\n        }\n      }\n    }\n  },\n  alternativeMachines: {\n    &#039;Test Run&#039;: {\n      &#039;No Run&#039;: {\n        initial: true,\n        transitions: {\n          &#039;Failing&#039;: {\n            targetState: &#039;Failing&#039;,\n            action: function(ctx) {\n           \/* Add actions. *\/\n            }\n          },\n          &#039;Failed&#039;: {\n            targetState: &#039;Failed&#039;,\n            action: function(ctx) {\n         \/* Add actions. *\/\n            }\n          },\n          &#039;Passing&#039;: {\n            targetState: &#039;Passing&#039;,\n            action: function(ctx) {\n          \/* Add actions. *\/\n            }\n          },\n          &#039;Passed&#039;: {\n            targetState: &#039;Passed&#039;,\n            action: function(ctx) {\n           \/* Add actions. *\/\n            }\n          }\n        }\n      },\n      Failing: {\n        transitions: {\n          &#039;Passing&#039;: {\n            targetState: &#039;Passing&#039;,\n            action: function(ctx) {\n           \/* Add actions . *\/\n            }\n          },\n          &#039;Passed&#039;: {\n            targetState: &#039;Passed&#039;,\n            action: function(ctx) {\n          \/* Add actions. *\/\n            }\n          },\n          &#039;Failed&#039;: {\n            targetState: &#039;Failed&#039;,\n            action: function(ctx) {\n           \/* Add actions. *\/\n            }\n          }\n        }\n      },\n      Passing: {\n        transitions: {\n          &#039;Failing&#039;: {\n            targetState: &#039;Passing&#039;,\n            action: function(ctx) {\n              workflow.check(false, workflow.i18n(&#039;Test Run has-read-only status which is defined based on assigned tests statuses&#039;));\n            }\n          },\n          &#039;Passed&#039;: {\n            targetState: &#039;Passed&#039;,\n            action: function(ctx) {\n           \/* Add actions. *\/\n            }\n          },\n          &#039;Failed&#039;: {\n            targetState: &#039;Failed&#039;,\n            action: function(ctx) {\n           \/* Add actions. *\/\n            }\n          }\n        }\n      },\n      Failed: {\n        transitions: {\n          &#039;Passing&#039;: {\n            targetState: &#039;Passing&#039;,\n            action: function(ctx) {\n           \/* Add actions. *\/\n            }\n          },\n          &#039;Passed&#039;: {\n            targetState: &#039;Passed&#039;,\n            action: function(ctx) {\n           \/* Add actions. *\/\n            }\n          },\n          &#039;Failing&#039;: {\n            targetState: &#039;Failed&#039;,\n            action: function(ctx) {\n           \/* Add actions. *\/\n            }\n          }\n        }\n      },\n      Passed: {\n        transitions: {\n          &#039;Passing&#039;: {\n            targetState: &#039;Passing&#039;,\n            action: function(ctx) {\n           \/* Add actions. *\/\n            }\n          },\n          &#039;Failed&#039;: {\n            targetState: &#039;Passed&#039;,\n            action: function(ctx) {\n          \/* Add actions. *\/\n            },\n          },\n          &#039;Failing&#039;: {\n            targetState: &#039;Failed&#039;,\n            action: function(ctx) {\n           \/* Add actions. *\/\n            }\n          }\n        }\n      }\n    }\n  },\n  requirements: {\n    Assignee: {\n      type: entities.User.fieldType\n    },\n    Status: {\n      type: entities.EnumField.fieldType,\n      InProgress: {\n        name: &#039;No Run&#039;\n      },\n      Failing: {\n        name: &#039;Failing&#039;\n      },\n      Passing: {\n        name: &#039;Passing&#039;\n      },\n      Passed: {\n        name: &#039;Passed&#039;\n      },\n      Failed: {\n        name: &#039;Failed&#039;\n      },\n    },\n    Type: {\n      type: entities.EnumField.fieldType,\n      TestRun: {\n        name: \"Test Run\"\n      },\n      TestExecution: {\n        name: \"Test Case Execution\"\n      }\n    },\n    Subtask: {\n      type: entities.IssueLinkPrototype,\n      name: &#039;Subtask&#039;,\n      inward: &#039;subtask of&#039;,\n      outward: &#039;parent for&#039;\n    },\n  }\n});\n <\/pre>\n<p>\n <\/details>\n<h1>Teststatistiken<\/h1>\n<p>Manchmal m\u00f6chte man sich die statistischen Daten zu einem Testzyklus ansehen. In diesem Beispiel haben wir die folgenden Kennzahlen implementiert:<\/p>\n<ul>\n<li>Gesamtzahl der Tests, die einem bestimmten Testlauf zugeordnet sind.<\/li>\n<li>Anzahl der erfolgreichen Tests (\u201ePassed\u201c).<\/li>\n<li>Anzahl der fehlgeschlagenen Tests (\u201eFailed\u201c).<\/li>\n<\/ul>\n<p><img decoding=\"async\" src=\"https:\/\/resources.jetbrains.com\/storage\/products\/blog\/wp-content\/uploads\/done5s720.gif\" alt=\"\" \/><br \/>\nDer folgende Code sorgt daf\u00fcr, dass diese Kennzahlen bei den folgenden \u00c4nderungen aktualisiert werden: Teststatus-\u00c4nderungen, Zuordnung eines neuen Tests zum Testlauf und Entfernen eines Tests aus dem Testlauf.<\/p>\n<details>\n<summary>\n        Codeblock ausklappen<br \/>\n    <\/summary>\n<p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-title=\"\">\n  exports.calculateStatuses = function(parent) {\n  var totalTR = 0;\n  var totalFailed = 0;\n  var totalPassed = 0;\n  if (!parent.links[&#039;parent for&#039;]) {\n    return;\n  } else {\n    parent.links[&#039;parent for&#039;].forEach(function(tr) {\n      totalTR++;\n      if (tr.Status.name == &#039;Passed&#039;) {\n        totalFailed++;\n      }\n      if (tr.Status.name == &#039;Failed&#039;) {\n        totalPassed++;\n      }\n    });\n    parent.fields[&#039;Total number of test cases&#039;] = totalTR;\n    parent.fields[&#039;Number of passed test cases&#039;] = totalPassed;\n    parent.fields[&#039;Number of failed test cases&#039;] = totalFailed;\n    return true;\n  }\n};\nexports.resetStatuses = function(testRun, testRunCopy) {\n   testRunCopy.fields[&#039;Total number of test cases&#039;] = testRun.fields[&#039;Total number of test cases&#039;];\n   testRunCopy.fields[&#039;Number of passed test cases&#039;] = 0;\n   testRunCopy.fields[&#039;Number of failed test cases&#039;] = 0;\n  return true;\n};\n<\/pre>\n<p>\n<\/details>\n<p>In unserem Fall wird dieser Code in mehreren Workflow-Regeln ausgel\u00f6st, z.\u00a0B. \u201eUpdate stats when links are adjusted\u201c (Statistiken aktualisieren, wenn Links angepasst werden), \u201eSwitch to the next test case \u201c (Zum n\u00e4chsten Testfall wechseln) und andere. Wenn Sie eigene Metriken verwenden m\u00f6chten, die Ihren spezifischen Anforderungen entsprechen, k\u00f6nnen Sie die erforderlichen benutzerdefinierten Felder hinzuf\u00fcgen und Ihre Workflow-Logik anpassen.<\/p>\n<h2>Issue-Tracker-Funktionen<\/h2>\n<p>Bei einem fehlgeschlagenen Test wollen Sie vielleicht eine separate Aufgabe erstellen und diese mit einem Ticket verkn\u00fcpfen, das die zugeh\u00f6rige Testfallausf\u00fchrung identifiziert. Um einen fehlgeschlagenen Test mit den zugeh\u00f6rigen Bugs zu verkn\u00fcpfen, k\u00f6nnen Sie entweder einen benutzerdefinierten Ticket-Linktyp verwenden oder in einem benutzerdefinierten Textfeld einen Verweis auf den Bug hinterlegen. Es ist m\u00f6glicherweise einfacher, f\u00fcr das Bug-Tracking ein separates YouTrack-Projekt anzulegen.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/TMS7.png\" alt=\"\" \/><\/p>\n<h2>M\u00f6gliche Verbesserungen<\/h2>\n<p>Sie k\u00f6nnen die Funktionalit\u00e4t von YouTrack erweitern, um besondere Gesch\u00e4ftsanforderungen zu erf\u00fcllen. Hier sind einige M\u00f6glichkeiten.<\/p>\n<h3>Vorhandenen Testlauf klonen<\/h3>\n<p>Manchmal kann es sehr hilfreich sein, einen vorhandenen Testlauf mit einigen kleinen \u00c4nderungen (z.\u00a0B. \u00c4nderung der zugewiesenen Version) erneut auszuf\u00fchren. Der Men\u00fcpunkt \u201eCreate Test Run copy\u201c (Testlaufkopie erstellen) ist genau f\u00fcr solche F\u00e4lle gedacht. Dieser Men\u00fcpunkt ist nur verf\u00fcgbar, wenn das Ticket den Typ \u201eTest Run\u201c (Testlauf) hat, und er l\u00f6st die folgenden Aktionen aus:<\/p>\n<ul>\n<li>Eine Kopie des Testlaufs sowie Kopien der diesem zugewiesenen Testfallausf\u00fchrungen erstellen.<\/li>\n<li>All newly created test case execution copies are assigned to the new test run using the \u2018parent-child\u2019 issue link type. Dar\u00fcber hinaus werden diese Kopien den urspr\u00fcnglichen Testf\u00e4llen mit dem Linktyp \u201eExecution\u201c (Ausf\u00fchrung) zugewiesen (um die R\u00fcckverfolgbarkeit zu gew\u00e4hrleisten).<\/li>\n<li>All statuses and statistics will be discarded for the newly created issue. <\/li>\n<\/ul>\n<p><img decoding=\"async\" src=\"https:\/\/resources.jetbrains.com\/storage\/products\/blog\/wp-content\/uploads\/done8s720.gif\" alt=\"\" \/><\/p>\n<p>Die obige Logik wird mithilfe der Aktionsregel \u201eCreate Test Run copy\u201c (Testlaufkopie erstellen) implementiert.<\/p>\n<details>\n<summary>\n        Codeblock ausklappen<br \/>\n    <\/summary>\n<p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-title=\"\">\nvar workflow = require(&#039;@jetbrains\/youtrack-scripting-api\/workflow&#039;);\nvar entities = require(&#039;@jetbrains\/youtrack-scripting-api\/entities&#039;);\nvar utils = require(&#039;..\/calculate-tms-stats\/utils&#039;);\n\nexports.rule = entities.Issue.action({\n  title: &#039;Create Test Run copy&#039;,\n  command: &#039;Test Run Creation&#039;,\n  guard: function(ctx) {\n    return ctx.issue.isReported &amp;&amp; (ctx.issue.Type.name == ctx.Type.TestRun.name);\n  },\n  action: function(ctx) {\n    var issue = ctx.issue;\n    var TestRunCopy = issue.copy(issue.project);\n    TestRunCopy.Status = ctx.Status.InProgress; \n    var oldTestList = issue.links[ctx.Subtask.outward];\n    oldTestList.forEach(function(v) {\n      var newTest = v.copy(v.project);\n      newTest.Status = ctx.Status.InProgress;\n      newTest.links[ctx.Subtask.inward].delete(issue);\n      newTest.links[ctx.Subtask.inward].add(TestRunCopy);\n    });\n    utils.resetStatuses(issue, TestRunCopy); \n    var newTestRunLink = &#039;<a href=\"&#039; + TestRunCopy.url + &#039;\"> &#039; + TestRunCopy.id + &#039;<\/a>&#039;;\n    var message = &#039;New Test Run has been created &#039; + newTestRunLink + &#039;.&#039;;\n    workflow.message(message);\n  },\n  requirements: {\n    Execution: {\n      type: entities.IssueLinkPrototype,\n      name: &#039;Execution&#039;,\n      inward: &#039;Execution&#039;,\n      outward: &#039;Assigned Test case or test suite&#039;\n    },\n    Subtask: {\n      type: entities.IssueLinkPrototype,\n      name: &#039;Subtask&#039;,\n      inward: &#039;subtask of&#039;,\n      outward: &#039;parent for&#039;\n    },\n    Type: {\n      type: entities.EnumField.fieldType,\n      TestRun: {\n        name: \"Test Run\"\n      },\n    },\n    Status: {\n      type: entities.EnumField.fieldType,\n      InProgress: {\n        name: &#039;No Run&#039;\n      },\n    }\n  }\n});\n <\/pre>\n<p>\n <\/details>\n<h2>Benutzeraktionen einschr\u00e4nken<\/h2>\n<p>Um m\u00f6gliche Fehler bei der Arbeit mit Testszenarien (z.\u00a0B. Verwendung des falschen Tickettyps) zu vermeiden, k\u00f6nnen Sie die Aktionen der Benutzer einschr\u00e4nken. Sie k\u00f6nnen beispielsweise Aktionen implementieren, um sicherzustellen, dass Benutzer Testf\u00e4lle mit Testl\u00e4ufen verkn\u00fcpfen. When the user links a test run to an issue, this action will check whether the linked issue type is \u2018Test Case\u2019 or \u2018Test Suite.\u2019 Ist dies nicht der Fall, l\u00f6st die Aktion eine Warnung aus, die den Benutzer daran hindert, fortzufahren.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/resources.jetbrains.com\/storage\/products\/blog\/wp-content\/uploads\/done9.720.gif\" alt=\"\" \/><\/p>\n<p>Der folgende Codeblock kann zum Workflow \u201ePopulate Test Run\u201c (Testlauf f\u00fcllen) hinzugef\u00fcgt werden.<\/p>\n<details>\n<summary>\n        Codeblock ausklappen<br \/>\n    <\/summary>\n<p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-title=\"\">\n var message = &#039;<a href=\"&#039; + TestCase.url + &#039;\"> &#039; + TestCase.id + &#039;<\/a>&#039;;\n      workflow.check((TestCase.Type.name == ctx.Type.TestCase.name) || (TestCase.Type.name == ctx.Type.TestSuite.name), workflow.i18n(&#039;\\&#039;Test Run\\&#039; can be linked to \\&#039;Test Case\\&#039; and \\&#039;Test Suite\\&#039; only, but {0} has \\&#039;{1}\\&#039; type!&#039;, message, TestCase.Type.name));\n    <\/pre>\n<p>\n    <\/details>\n<p>Wie <a href=\"#ref2\">oben<\/a> erw\u00e4hnt sollte der Testlaufstatus nur gelesen und nicht ge\u00e4ndert werden, da er vom Ergebnis der Testausf\u00fchrungen abh\u00e4ngt. Dies kann auf einfache Weise sichergestellt werden, indem ein Codeblock eingef\u00fcgt wird, der bei Tickets vom Typ \u201eTestlauf\u201c manuelle Status\u00e4nderungen verhindert.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/done10s720.gif\" alt=\"\" \/><br \/>\nBeispielsweise kann der Abschnitt \u201etransitions\u201c des Tickettyps \u201eTest Run\u201c im Workflow \u201estatus-management\u201c wie folgt angepasst werden:<\/p>\n<details>\n<summary>\n        Codeblock ausklappen<br \/>\n    <\/summary>\n<p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-title=\"\">\n   &#039;Failing&#039;: {\n            targetState: &#039;Failing&#039;,\n            action: function(ctx) {\n              workflow.check(false, workflow.i18n(&#039;Test run has read-only status which is defined based on assigned tests statuses&#039;));\n            }\n          },\n          ...\n        }\n<\/pre>\n<p>\n<\/details>\n<h2>Berichte und R\u00fcckverfolgung<\/h2>\n<h3>Berichte<\/h3>\n<p>Wenn ein Testzyklus abgeschlossen ist, m\u00f6chten Sie m\u00f6glicherweise die Ergebnisse analysieren. Die YouTrack-Berichtsfunktion leistet Ihnen dabei hervorragende Dienste. You can select the report type, which will display key information related to the test management procedure. F\u00fcr diese Demonstration f\u00fcgen wir dem Dashboard zwei Berichte hinzu:<\/p>\n<ul>\n<li>\n<em><b>Kumulativer-Fluss-Bericht, gefiltert nach dem Feld \u201eVersion\u201c.<\/b><\/em> Dieser Statusbericht bezieht sich auf eine bestimmte Produktversion. Er bildet auf einer Zeitachse wichtige Werte wie die Anzahl der Tests mit den verschiedenen Statuswerten \u2013 Passed, Failed und No Run \u2013 ab. Um Daten f\u00fcr mehrere Versionen anzuzeigen, erstellen Sie einen Bericht f\u00fcr jede Version. Es kann zweckm\u00e4\u00dfig sein, alle Berichte zum Dashboard hinzuzuf\u00fcgen, um alle Daten an einem Ort zu haben.<\/p>\n<h3>Einrichten des Berichts:<\/h3>\n<p><a href=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/TMS11.png\" rel=\"attachment wp-att-6366\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/TMS11.png\" alt=\"ApplyingCommandForSubsystem\" \/><\/a><\/p>\n<h3>Ergebnisse des Berichts:<\/h3>\n<p><a href=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/TMS12.png\" rel=\"attachment wp-att-6366\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/TMS12.png\" alt=\"ApplyingCommandForSubsystem\" \/><\/a><\/p>\n<\/li>\n<li><em> <b>Ticketverteilungsbericht.<\/b><\/em> Dieser Bericht ist eine Momentaufnahme, die wichtige Kennzahlen (z.\u00a0B. die Anzahl der Testl\u00e4ufe pro Status) f\u00fcr mehrere Produktversionen enth\u00e4lt. Anhand der Berichtsergebnisse in diesem Beispiel k\u00f6nnen Sie mehrere Versionen miteinander vergleichen und die Versionsstabilit\u00e4t analysieren.<br \/>\n<h3>Einrichten des Berichts:<\/h3>\n<p><a href=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/TMS13.png\" rel=\"attachment wp-att-6366\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/TMS13.png\" alt=\"ApplyingCommandForSubsystem\" \/><\/a><\/p>\n<h3>Ergebnisse des Berichts:<\/h3>\n<p><a href=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/re_res_cut.png\" rel=\"attachment wp-att-6366\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/re_res_cut.png\" alt=\"ApplyingCommandForSubsystem\" \/><\/a>\n <\/li>\n<\/ul>\n<h2>R\u00fcckverfolgung <\/h2>\n<p>Da YouTrack f\u00fcr jedes Ticket vom Typ \u201eTest Execution\u201c wichtige Informationen zum Testzyklus speichert, k\u00f6nnen Sie jederzeit auf den Testverlauf zugreifen und relevante Fehler identifizieren.<br \/>\nWenn Sie einen Testfall haben, k\u00f6nnen Sie auf alle Testausf\u00fchrungen zugreifen, die sich auf diesen Testfall beziehen.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/TMS15.png\" alt=\"\" \/><\/p>\n<p>Von der Testfallausf\u00fchrung ausgehend k\u00f6nnen Sie auf den Testlauf zugreifen.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/TMS16.png\" alt=\"\" \/><\/p>\n<p>Bei einer fehlgeschlagenen Testfallausf\u00fchrung haben Sie immer Zugriff auf die Liste der zugeh\u00f6rigen Fehler.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/TMS17.png\" alt=\"\" \/><\/p>\n<p>Sie k\u00f6nnen jederzeit die Quellen f\u00fcr alle in diesem Artikel beschriebenen Workflows aus unserem <a href=\"http:\/\/youtrack-community.herokuapp.com\/\" target=\"_blank\" rel=\"noopener\">Repo<\/a> herunterladen. Wenn Sie sich \u00fcber andere Workflows austauschen m\u00f6chten, laden wir Sie herzlich ein, sich unserer <a href=\"http:\/\/youtrack-community.herokuapp.com\/\" target=\"_blank\" rel=\"noopener\">YouTrack-Workflow-Community<\/a> in Slack anzuschlie\u00dfen.<\/p>\n","protected":false},"author":1132,"featured_media":93923,"comment_status":"closed","ping_status":"closed","template":"","categories":[808],"tags":[],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/youtrack\/91852"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/youtrack"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/types\/youtrack"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/users\/1132"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/comments?post=91852"}],"version-history":[{"count":5,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/youtrack\/91852\/revisions"}],"predecessor-version":[{"id":136802,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/youtrack\/91852\/revisions\/136802"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/media\/93923"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/media?parent=91852"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/categories?post=91852"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/tags?post=91852"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/cross-post-tag?post=91852"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}