1"use strict";(self.webpackChunkstryker_mutator_github_io=self.webpackChunkstryker_mutator_github_io||[]).push([["6626"],{41042:function(e,t,r){r.r(t),r.d(t,{assets:function(){return l},contentTitle:function(){return a},default:function(){return h},frontMatter:function(){return o},metadata:function(){return n},toc:function(){return d}});var n=r(29069),s=r(91987),i=r(67008);let o={slug:"stryker-net-mtp-runner",title:"Introducing the Microsoft Testing Platform runner for Stryker.NET",authors:"richardwerkman",tags:["stryker-net"]},a,l={authorsImageUrls:[void 0]},d=[{value:"\u{1F680} Microsoft Testing Platform runner (preview)",id:"-microsoft-testing-platform-runner-preview",level:2},{value:"How to enable it",id:"how-to-enable-it",level:3},{value:"Performance benefits",id:"performance-benefits",level:3},{value:"Preview status \u2014 what still needs work",id:"preview-status--what-still-needs-work",level:3},{value:"We need your feedback!",id:"we-need-your-feedback",level:3},{value:"\u{1F4F0} Other noteworthy updates",id:"-other-noteworthy-updates",level:2},{value:"New mutators",id:"new-mutators",level:3},{value:"YAML config file support",id:"yaml-config-file-support",level:3},{value:"\u{1F32F} That's a wrap",id:"-thats-a-wrap",level:2}];function c(e){let t={a:"a",code:"code",em:"em",h2:"h2",h3:"h3",hr:"hr",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)(t.p,{children:["It has been a while since our last Stryker.NET blog post. The team has been quietly shipping a lot of improvements, and today we want to highlight the biggest one: ",(0,s.jsx)(t.strong,{children:"Microsoft Testing Platform (MTP) support"}),", now available in preview starting from Stryker.NET 4.13."]}),"\n",(0,s.jsx)(t.p,{children:"We also have a roundup of other noteworthy features that have landed since our last update."}),"\n","\n",(0,s.jsx)(t.p,{children:"Are you already using Stryker.NET? Update to the latest version:"}),"\n",(0,s.jsx)(t.p,{children:"Global install:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-shell",children:"dotnet tool update dotnet-stryker --global\n"})}),"\n",(0,s.jsx)(t.p,{children:"Local install:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-shell",children:"dotnet tool update dotnet-stryker --local\n"})}),"\n",(0,s.jsx)(t.h2,{id:"-microsoft-testing-platform-runner-preview",children:"\u{1F680} Microsoft Testing Platform runner (preview)"}),"\n",(0,s.jsxs)(t.p,{children:["Stryker.NET has long relied on ",(0,s.jsx)(t.strong,{children:"VSTest"})," as its test runner. VSTest works well, but it has a fundamental limitation: Stryker has to spin up a brand new VSTest process for every mutation test run. On large test suites, that startup overhead adds up quickly."]}),"\n",(0,s.jsxs)(t.p,{children:["Microsoft has been building a modern alternative called the ",(0,s.jsx)(t.a,{href:"https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-platform-intro",children:"Microsoft Testing Platform (MTP)"}),". MTP is already being adopted by all the major testing frameworks (MSTest, NUnit, and xUnit v3) and it is the ",(0,s.jsx)(t.em,{children:"only"})," supported runner for newer frameworks such as ",(0,s.jsx)(t.a,{href:"https://github.com/thomhurst/TUnit",children:"TUnit"}),". Until now, projects using these frameworks could not use Stryker.NET at all."]}),"\n",(0,s.jsxs)(t.p,{children:["We're excited to announce that ",(0,s.jsx)(t.strong,{children:"MTP support is now available in preview"})," in Stryker.NET 4.13."]}),"\n",(0,s.jsx)(t.h3,{id:"how-to-enable-it",children:"How to enable it"}),"\n",(0,s.jsxs)(t.p,{children:["Enable the MTP runner by passing ",(0,s.jsx)(t.code,{children:"--test-runner mtp"})," on the command line:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-shell",children:"dotnet stryker --test-runner mtp\n"})}),"\n",(0,s.jsxs)(t.p,{children:["Or add it to your ",(0,s.jsx)(t.code,{children:"stryker-config.json"}),":"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-json",children:'{\n "stryker-config": {\n "test-runner": "mtp"\
1n }\n}\n'})}),"\n",(0,s.jsxs)(t.p,{children:["Or in ",(0,s.jsx)(t.code,{children:"stryker-config.yaml"}),":"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"stryker-config:\n test-runner: mtp\n"})}),"\n",(0,s.jsx)(t.h3,{id:"performance-benefits",children:"Performance benefits"}),"\n",(0,s.jsx)(t.p,{children:"Because MTP is designed to be embedded and extended rather than being a self-contained external process, Stryker can keep the test runner alive across multiple mutation test runs. This eliminates the per-run startup cost that made VSTest slow on larger projects, and is expected to provide a significant performance improvement."}),"\n",(0,s.jsx)(t.h3,{id:"preview-status--what-still-needs-work",children:"Preview status \u2014 what still needs work"}),"\n",(0,s.jsxs)(t.p,{children:["The MTP runner is ",(0,s.jsx)(t.strong,{children:"still in preview"}),". Coverage analysis is partially implemented: Stryker can already filter out mutants that are not covered by any test, but it cannot yet filter individual test cases per mutant. Full per-test coverage analysis is still being worked on."]}),"\n",(0,s.jsxs)(t.p,{children:["Additionally, the MTP runner does not yet support ",(0,s.jsx)(t.strong,{children:".NET Framework"})," test projects (see ",(0,s.jsx)(t.a,{href:"https://github.com/stryker-mutator/stryker-net/issues/3421",children:"#3421"}),")."]}),"\n",(0,s.jsx)(t.h3,{id:"we-need-your-feedback",children:"We need your feedback!"}),"\n",(0,s.jsxs)(t.p,{children:["Because this is a preview feature, your feedback is essential. If you encounter any issues or unexpected results when using the MTP runner, please ",(0,s.jsx)(t.a,{href:"https://github.com/stryker-mutator/stryker-net/issues",children:"open an issue on GitHub"})," or reach out on our ",(0,s.jsx)(t.a,{href:"https://join.slack.com/t/stryker-mutator/shared_invite/enQtOTUyMTYyNTg1NDQ0LTU4ODNmZDlmN2I3MmEyMTVhYjZlYmJkOThlNTY3NTM1M2QxYmM5YTM3ODQxYmJjY2YyYzllM2RkMmM1NjNjZjM",children:"Slack channel"}),". We want to make this stable as soon as possible, and every bug report helps!"]}),"\n",(0,s.jsx)(t.hr,{}),"\n",(0,s.jsx)(t.h2,{id:"-other-noteworthy-updates",children:"\u{1F4F0} Other noteworthy updates"}),"\n",(0,s.jsx)(t.p,{children:"A lot has changed since our February 2024 blog post. Here are the highlights."}),"\n",(0,s.jsx)(t.h3,{id:"new-mutators",children:"New mutators"}),"\n",(0,s.jsx)(t.p,{children:"Two new mutation categories have been added to Stryker.NET's arsenal."}),"\n",(0,s.jsxs)(t.p,{children:[(0,s.jsx)(t.strong,{children:"String method mutations"})," (",(0,s.jsx)(t.code,{children:"stringmethod"}),"): Stryker now mutates common string manipulation methods. For example:"]}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Original"}),(0,s.jsx)(t.th,{children:"Mutated"})]})}),(0,s.jsxs)(t.tbody,{children:[(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"ToUpper()"})}),(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"ToLower()"})})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"ToLower()"})}),(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"ToUpper()"})})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"Trim()"})}),(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:'""'})})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"TrimStart()"})}),(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"TrimEnd()"})})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"TrimEnd()"})}),(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"TrimStart()"})})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"StartsWith()"})}),(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"EndsWith()"})})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"EndsWith()"})}),(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"StartsWith()"})})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"PadLeft()"})}),(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"PadRight()"})})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"IndexOf()"})}),(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"LastIndexOf()"})})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"Substring()"})}),(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:'""'})})]})]})]}),"\n",(0,s.jsx)(t.p,{children:"These mutations are particularly good at catching code where the direction or casing of a string operation was never actually tested."}),"\n",(0,s.jsxs)(t.p,{children:[(0,s.jsx)(t.strong,{children:"List pattern mutations"}),": Stryker now mutates C# list pattern syntax. When code uses ",(0,s.jsx)(t.code,{children:"is [...]"})," patterns to match the structure of a collection, Stryker will test that the pattern is actually meaningful by swapping or removing elements. This brings mutation testing to a modern and increasingly popular C# feature."]}),"\n",(0,s.jsx)(t.h3,{id:"yaml-config-file-support",children:"YAML config file support"}),"\n",(0,s.jsxs)(t.p,{children:["Stryker configuration files can now be written in ",(0,s.jsx)(t.strong,{children:"YAML"})," in addition to JSON. If you prefer YAML, simply create a ",(0,s.jsx)(t.code,{children:"stryker
1-config.yaml"})," (or ",(0,s.jsx)(t.code,{children:"stryker-config.yml"}),") file alongside your project:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"stryker-config:\n project: 'MyProject.csproj'\n reporters:\n - html\n - progress\n thresholds:\n high: 80\n low: 60\n"})}),"\n",(0,s.jsx)(t.p,{children:"The file will be picked up automatically without any additional options."}),"\n",(0,s.jsx)(t.hr,{}),"\n",(0,s.jsx)(t.h2,{id:"-thats-a-wrap",children:"\u{1F32F} That's a wrap"}),"\n",(0,s.jsx)(t.p,{children:"There is a lot to explore here. We are especially excited about the MTP runner and the doors it opens for teams using xUnit v3, NUnit's new MTP mode, or the excellent TUnit framework. Give it a try and let us know how it goes!"}),"\n",(0,s.jsxs)(t.p,{children:["As always, we'd love to hear your thoughts on ",(0,s.jsx)(t.a,{href:"https://join.slack.com/t/stryker-mutator/shared_invite/enQtOTUyMTYyNTg1NDQ0LTU4ODNmZDlmN2I3MmEyMTVhYjZlYmJkOThlNTY3NTM1M2QxYmM5YTM3ODQxYmJjY2YyYzllM2RkMmM1NjNjZjM",children:"our Slack channel"}),", open an ",(0,s.jsx)(t.a,{href:"https://github.com/stryker-mutator/stryker-net/issues",children:"issue on GitHub"}),", or send us a ",(0,s.jsx)(t.a,{href:"https://twitter.com/stryker_mutator/",children:"tweet"}),"."]})]})}function h(e={}){let{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},67008:function(e,t,r){r.d(t,{R:function(){return o},x:function(){return a}});var n=r(71763);let s={},i=n.createContext(s);function o(e){let t=n.useContext(i);return n.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),n.createElement(i.Provider,{value:t},e.children)}},29069:function(e){e.exports=JSON.parse('{"permalink":"/blog/stryker-net-mtp-runner","editUrl":"https://github.com/stryker-mutator/stryker-mutator.github.io/edit/develop/blog/2026-03-13-stryker-net-mtp-runner.mdx","source":"@site/blog/2026-03-13-stryker-net-mtp-runner.mdx","title":"Introducing the Microsoft Testing Platform runner for Stryker.NET","description":"It has been a while since our last Stryker.NET blog post. The team has been quietly shipping a lot of improvements, and today we want to highlight the biggest one: Microsoft Testing Platform (MTP) support, now available in preview starting from Stryker.NET 4.13.","date":"2026-03-13T00:00:00.000Z","tags":[{"inline":true,"label":"stryker-net","permalink":"/blog/tags/stryker-net"}],"readingTime":3.69,"hasTruncateMarker":true,"authors":[{"name":"Richard Werkman","title":"Stryker.NET Team","socials":{"github":"https://github.com/richardwerkman"},"imageURL":"https://avatars.githubusercontent.com/u/14224500","key":"richardwerkman","page":null}],"frontMatter":{"slug":"stryker-net-mtp-runner","title":"Introducing the Microsoft Testing Platform runner for Stryker.NET","authors":"richardwerkman","tags":["stryker-net"]},"unlisted":false,"prevItem":{"title":"Stryker4s 1.0: Mutation testing across the Scala ecosystem","permalink":"/blog/stryker4s-v1"},"nextItem":{"title":"Announcing the Stryker VS Code Plugin","permalink":"/blog/vscode-plugin"}}')}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.