1"use strict";(self.webpackChunkstryker_mutator_github_io=self.webpackChunkstryker_mutator_github_io||[]).push([["8781"],{1760:function(e,t,n){n.r(t),n.d(t,{assets:function(){return d},contentTitle:function(){return o},default:function(){return c},frontMatter:function(){return l},metadata:function(){return r},toc:function(){return a}});var r=n(36680),i=n(94686),s=n(23191);let l={slug:"2021-30-10-announcing-stryker-net-1",title:"Announcing Stryker.NET 1.0",authors:"richardwerkman",tags:["stryker.net","release","mutation testing","stryker mutator","stryker-js"]},o="Announcing Stryker.NET 1.0 - No more beta!",d={authorsImageUrls:[void 0]},a=[{value:"\u{1F4A5} Breaking changes",id:"-breaking-changes",level:2},{value:"\u23ED Updated runtime",id:"-updated-runtime",level:3},{value:"\u23ED Options rework",id:"-options-rework",level:3},{value:"Multi value options",id:"multi-value-options",level:4},{value:"Options migration guide",id:"options-migration-guide",level:4},{value:"\u{1F680} What's new?",id:"-whats-new",level:2},{value:"Statement removal mutator",id:"statement-removal-mutator",level:3},{value:"Allow failing tests",id:"allow-failing-tests",level:3},{value:"Mutant filtering",id:"mutant-filtering",level:3},{value:"Ignore mutations",id:"ignore-mutations",level:3},{value:"MsBuild path option",id:"msbuild-path-option",level:3},{value:"Target framework",id:"target-framework",level:3},{value:"Filter test cases",id:"filter-test-cases",level:3},{value:"Use Source Link for dashboard reporter",id:"use-source-link-for-dashboard-reporter",level:3},{value:"Block removal mutations",id:"block-removal-mutations",level:3},{value:"\u{1F41B} Bug fixes",id:"-bug-fixes",level:2},{value:"No more mutated assembly on disk after Stryker run",id:"no-more-mutated-assembly-on-disk-after-stryker-run",level:3},{value:"\u{1F46A} Team expansion",id:"-team-expansion",level:2},{value:"\u{1F389} Thank you",id:"-thank-you",level:2}];function h(e){let t={a:"a",blockquote:"blockquote",code:"code",em:"em",h2:"h2",h3:"h3",h4:"h4",img:"img",li:"li",p:"p",pre:"pre",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.p,{children:"We're proud to announce the first major release of Stryker.NET: 1.0. It comes with exciting new features and an overhaul of how you interact with the Stryker CLI. With the release of Stryker 1.0, we wanted to create a cohesive and intuitive user experience."}),"\n","\n",(0,i.jsxs)(t.p,{children:["If you're new to mutation testing, it's a way to measure your tests' effectiveness. A mutation testing framework will make small changes, called ",(0,i.jsx)(t.em,{children:"mutants"}),', one by one in your source code. Then it will run your tests to see if one of them fails. If so, you just "killed" that mutant; if not, it "survived". If too many mutants survive, you probably want to improve your tests. The mutation testing report will give you insides into the test cases you may have missed. If this all sounds complicated, please take a look at ',(0,i.jsx)(t.a,{href:"/docs/General/example",children:"our RoboCoasters \u{1F916}\u{1F3A2} example"}),"."]}),"\n",(0,i.jsxs)(t.p,{children:["If you're new to Stryker.NET, please follow our ",(0,i.jsx)(t.a,{href:"/docs/stryker-net/getting-started/",children:"Getting started guide"}),". Are you already using Stryker.NET? Update to the latest version with the following command:"]}),"\n",(0,i.jsx)(t.p,{children:"Global install:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-shell",children:"dotnet tool update dotnet-stryker --global\n"})}),"\n",(0,i.jsx)(t.p,{children:"Project install:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-shell",children:"dotnet tool update dotnet-stryker --local\n"})}),"\n",(0,i.jsx)(t.p,{children:"With that out of the way, let's dive into the new stuff!"}),"\n",(0,i.jsx)(t.h2,{id:"-breaking-changes",children:"\u{1F4A5} Breaking changes"}),"\n",(0,i.jsx)(t.h3,{id:"-updated-runtime",children:"\u23ED Updated runtime"}),"\n",(0,i.jsx)(t.p,{children:"The .NET runtime for Stryker.NET has been updated from 3.1 to 5.0."}),"\n",(0,i.jsx)(t.p,{children:"This update should have some performance benefits, and it will help with developing Stryker.NET in the future."}),"\n",(0,i.jsxs)(t.p,{children:["Please ",(0,i.jsx)(t.a,{href:"https://dotnet.microsoft.com/download/dotnet/5.0",children:"download and install .NET 5.0"}
1)," or update your pipeline to support .NET 5."]}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.em,{children:"Note that you do not have to update your application to use dotnet 5. Dotnet 5 is only a runtime requirement for Stryker to be able to run on your system."})}),"\n",(0,i.jsx)(t.h3,{id:"-options-rework",children:"\u23ED Options rework"}),"\n",(0,i.jsx)(t.p,{children:"Most options have been renamed or work differently."}),"\n",(0,i.jsx)(t.p,{children:"A fundamental difference is how you pass multi-value options from the command line."}),"\n",(0,i.jsx)(t.h4,{id:"multi-value-options",children:"Multi value options"}),"\n",(0,i.jsx)(t.p,{children:"The old annotation for passing multi-value options was confusing and not based on any standards. For example, this is how you provided multiple reporters pre 1.0 \u{1F44E}"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-shell",children:"dotnet stryker --reporters \"['html', 'progress']\"\n"})}),"\n",(0,i.jsx)(t.p,{children:"From 1.0 onward, this now looks like \u{1F44D}"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-shell",children:'dotnet stryker --reporter "html" --reporter "progress"\n'})}),"\n",(0,i.jsx)(t.h4,{id:"options-migration-guide",children:"Options migration guide"}),"\n",(0,i.jsx)(t.p,{children:"Most options have a new name. We have also decided that some options either don't belong on the commandline or don't belong in the configuration file. For example, an API key should not be stored in the configuration file so that possibility has been removed."}),"\n",(0,i.jsx)(t.p,{children:"Options migration overview:"}),"\n",(0,i.jsxs)(t.table,{children:[(0,i.jsx)(t.thead,{children:(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.th,{children:"Old cli"}),(0,i.jsx)(t.th,{children:"New cli"}),(0,i.jsx)(t.th,{children:"Old json"}),(0,i.jsx)(t.th,{children:"New json"})]})}),(0,i.jsxs)(t.tbody,{children:[(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"config-file-path"}),(0,i.jsx)(t.td,{children:"f | config-file"}),(0,i.jsx)(t.td,{children:"\u274C"}),(0,i.jsx)(t.td,{children:"\u274C"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"max-concurrent-testrunners"}),(0,i.jsx)(t.td,{children:"c | concurrency"}),(0,i.jsx)(t.td,{children:"max-concurrent-testrunners"}),(0,i.jsx)(t.td,{children:"concurrency"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"dev-mode"}),(0,i.jsx)(t.td,{children:"dev-mode"}),(0,i.jsx)(t.td,{children:"dev-mode"}),(0,i.jsx)(t.td,{children:"\u274C"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"solution-path"}),(0,i.jsx)(t.td,{children:"s | solution"}),(0,i.jsx)(t.td,{children:"solution-path"}),(0,i.jsx)(t.td,{children:"solution"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"log-file"}),(0,i.jsx)(t.td,{children:"L | log-to-file"}),(0,i.jsx)(t.td,{children:"log-file"}),(0,i.jsx)(t.td,{children:"\u274C"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"log-level"}),(0,i.jsx)(t.td,{children:"V | verbosity"}),(0,i.jsx)(t.td,{children:"log-level"}),(0,i.jsx)(t.td,{children:"verbosity"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"mutation-level"}),(0,i.jsx)(t.td,{children:"l | mutation-level"}),(0,i.jsx)(t.td,{children:"mutation-level"}),(0,i.jsx)(t.td,{children:"mutation-level"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"threshold-high"}),(0,i.jsx)(t.td,{children:"\u274C"}),(0,i.jsx)(t.td,{children:"thresholds.high"}),(0,i.jsx)(t.td,{children:"thresholds.high"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"threshold-low"}),(0,i.jsx)(t.td,{children:"\u274C"}),(0,i.jsx)(t.td,{children:"thresholds.low"}),(0,i.jsx)(t.td,{children:"thresholds.low"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"threshold-break"}),(0,i.jsx)(t.td,{children:"b | break-at"}),(0,i.jsx)(t.td,{children:"thresholds.break"}),(0,i.jsx)(t.td,{children:"thresholds.break"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"reporters"}),(0,i.jsx)(t.td,{children:"r | reporter (flag allowed multiple times)"}),(0,i.jsx)(t.td,{children:"reporters"}),(0,i.jsx)(t.td,{children:"reporters"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"project-file"}),(0,i.jsx)(t.td,{children:"p | project"}),(0,i.jsx)(t.td,{children:"project-file"}),(0,i.jsx)(t.td,{children:"project"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"diff"}),(0,i.jsx)(t.td,{children:"since"}),(0,i.jsx)(t.td,{children:"diff"}),(0,i.jsx)(t.td,{children:"since"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"timeout-ms"}),(0,i.jsx)(t.td,{children:"\u274C"}),(0,i.jsx)(t.td,{children:"timeout-ms"}),(0,i.jsx)(t.td,{children:"additional-timeout"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"excluded-mutations"}),(0,i.jsx)(t.td,{children:"\u274C"}),(0,i.jsx)(t.td,{children:"excluded-mutations"}),(0,i.jsx)(t.td,{children:"ignore-mutations"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"ignore-methods"}),(0,i.jsx)(t.td,{children:"\u274C"}),(0,i.jsx)(t.td,{children:"ignore-methods"}),(0,i.jsx)(t.td,{children:"ignore-methods"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"mutate"}),(0,i.jsx)(t.td,{children:"m | mutate"}),(0,i.jsx)(t.td,{children:"mutate"}),(0,i.jsx)(t.td,{children:"mutate"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"language-version"}),(0,i.jsx)(t.td,{children:"\u274C"}),(0,i.jsx)(t.td,{children:"language-version"}),(0,i.jsx)(t.td,{children:"language-version"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"coverage-analysis"}),(0,i.jsx)(t.td,{children:"\u274C"}),(0,i.jsx)(t.td,{children:"coverage-analysis"}),(0,i.jsx)(t.td,{children:"coverage-analysis"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"abort-test-on-fail"}),(0,i.jsx)(t.td,{children:"\u274C"}),(0,i.jsx)(t.td,{children:"abort-test-on-fail"}),(0,i.jsx)(t.td,{children:"disable-bail"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"disable-testing-mix-mutations"}),(0,i.jsx)(t.td,{children:"\u274C"}),(0,i.jsx)(t.td,{children:"disable-testing-mix-mutations"}),(0,i.jsx)(t.td,{children:"disable-mix-mutants"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"test-projects"}),(0,i.jsx)(t.td,{children:"\u274C"}),(0,i.jsx)(t.td,{children:"test-projects"}),(0,i.jsx)(t.td,{children:"test-projects"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"dashboard-url"}),(0,i.jsx)(t.td,{children:"\u274C"}),(0,i.jsx)(t.td,{children:"dashboard-url"}),(0,i.jsx)(t.td,{children:"dashboard-url"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"dashboard-api-key"}),(0,i.jsx)(t.td,{children:"dashboard-api-key"}),(0,i.jsx)(t.td,{children:"dashboard-api-key"}),(0,i.jsx)(t.td,{children:"\u274C"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"project-name"}),(0,i.jsx)(t.td,{children:"\u274C"}),(0,i.jsx)(t.td,{children:"dashboard-project"}),(0,i.jsx)(t.td,{children:"project-info.name"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"module-name"}),(0,i.jsx)(t.td,{children:"\u274C"}),(0,i.jsx)(t.td,{children:"dashboard-module"}),(0,i.jsx)(t.td,{children:"project-info.module"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"dashboard-version"}),(0,i.jsx)(t.td,{children:"v | version"}),(0,i.jsx)(t.td,{children:"dashboard-version"}),(0,i.jsx)(t.td,{children:"project-info.version"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"diff-ignore-files"}),(0,i.jsx)(t.td,{children:"\u274C"}),(0,i.jsx)(t.td,{children:"diff-ignore-files"}),(0,i.jsx)(t.td,{children:"since.ignore-changes-in"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"azure-storage-url"}),(0,i.jsx)(t.td,{children:"\u274C"}),(0,i.jsx)(t.td,{children:"azure-storage-url"}),(0,i.jsx)(t.td,{children:"baseline.azure-fileshare-url"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"dashboard-fallback-version"}),(0,i.jsx)(t.td,{children:"\u274C"}),(0,i.jsx)(t.td,{children:"dashboard-fallback-version"}),(0,i.jsx)(t.td,{children:"baseline.fallback-version"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"baseline-storage-location"}),(0,i.jsx)(t.td,{children:"\u274C"}),(0,i.jsx)(t.td,{children:"baseline-storage-location"}),(0,i.jsx)(t.td,{children:"baseline.provider"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"dashboard-compare"}),(0,i.jsx)(t.td,{children:"with-baseline"}),(0,i.jsx)(t.td,{children:"dashboard-compare"}),(0,i.jsx)(t.td,{children:"baseline"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"git-diff-target"}),(0,i.jsx)(t.td,{children:"--since ..."}),(0,i.jsx)(t.td,{children:"git-diff-target"}),(0,i.jsx)(t.td,{children:"since.target"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"azure-storage-sas"}),(0,i.jsx)(t.td,{children:"azure-fileshare-sas"}),(0,i.jsx)(t.td,{children:"azure-storage-sas"}),(0,i.jsx)(t.td,{children:"\u274C"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"files-to-exclude"}),(0,i.jsx)(t.td,{children:"\u274C"}),(0,i.jsx)(t.td,{children:"\u274C"}),(0,i.jsx)(t.td,{children:"\u274C"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"test-runner"}),(0,i.jsx)(t.td,{children:"\u274C"}),(0,i.jsx)(t.td,{children:"\u274C"}),(0,i.jsx)(t.td,{children:"\u274C"})]})]})]}),"\n",(0,i.jsx)(t.p,{children:"\u274C means the option has been removed."}),"\n",(0,i.jsx)(t.h2,{id:"-whats-new",children:"\u{1F680} What's new?"}
1),"\n",(0,i.jsx)(t.p,{children:"This release comes packed with new features! Let's walk through them all:"}),"\n",(0,i.jsx)(t.h3,{id:"statement-removal-mutator",children:"Statement removal mutator"}),"\n",(0,i.jsx)(t.p,{children:"We introduced a new mutator that removes statements that otherwise would have been untouched by other mutators."}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.img,{src:n(42853).A+"",width:"880",height:"465"})}),"\n",(0,i.jsx)(t.p,{children:"The mutator will remove the following statements:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.code,{children:"return"})}),"\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.code,{children:"break"})}),"\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.code,{children:"continue"})}),"\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.code,{children:"goto"})}),"\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.code,{children:"throw"})}),"\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.code,{children:"yield return"})}),"\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.code,{children:"yield break"})}),"\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.code,{children:"expression"})}),"\n"]}),"\n",(0,i.jsx)(t.h3,{id:"allow-failing-tests",children:"Allow failing tests"}),"\n",(0,i.jsxs)(t.p,{children:["It's now allowed to start a mutation test run even with failing tests. Stryker will try to make the best of the situation by marking mutants covered by ",(0,i.jsx)(t.code,{children:"initially failing tests"})," as ",(0,i.jsx)(t.code,{children:"survived"}),"."]}),"\n",(0,i.jsx)(t.h3,{id:"mutant-filtering",children:"Mutant filtering"}),"\n",(0,i.jsx)(t.p,{children:"It's now possible to filter mutants at the source code level using special comments. This filtering gives the most fine-grained level of control."}),"\n",(0,i.jsxs)(t.p,{children:["The syntax for the comments is: ",(0,i.jsx)(t.code,{children:"Stryker [disable|restore][once][all| mutator list][: reason for disabling]"})]}),"\n",(0,i.jsxs)(t.p,{children:[(0,i.jsx)(t.code,{children:"// Stryker disable all"})," Disables all mutants from that line on."]}),"\n",(0,i.jsxs)(t.p,{children:[(0,i.jsx)(t.code,{children:"// Stryker restore all"})," re-enables all mutants from that line on."]}),"\n",(0,i.jsxs)(t.p,{children:[(0,i.jsx)(t.code,{children:"// Stryker disable once all"})," will only disable mutants on the next line."]}),"\n",(0,i.jsxs)(t.p,{children:[(0,i.jsx)(t.code,{children:"// Stryker disable once Arithmetic,Update"})," will only disable Arithmetic and Update mutants on the next line"]}),"\n",(0,i.jsx)(t.p,{children:"Example:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-csharp",children:"var i = 0;\nvar y = 10;\n// Stryker disable all : for explanatory reasons\ni++; // won't be mutated\ny++; // won't be mutated\n// Stryker restore all\ni--; // will be mutated\n// Stryker disable once all\ny--; // won't be mutated\ni++; // will be mutated\n// Stryker disable once Arithmetic\ny++; // will be mutated\n// Stryker disable once Arithmetic,Update\ni--; // won't be mutated\n"})}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.em,{children:"Note that this feature is scope aware. If you disable mutators inside a method, the scope will not leak outside the method, even if there is more code below."})}),"\n",(0,i.jsx)(t.h3,{id:"ignore-mutations",children:"Ignore mutations"}),"\n",(0,i.jsxs)(t.p,{children:["The ",(0,i.jsx)(t.code,{children:"ignore-mutations"})," option now offers more fine-grained control. Before v1.0 it was possible to ignore complete mutators. Now it's possible to ignore specific mutants inside these mutators as well."]}),"\n",(0,i.jsx)(t.p,{children:"Example:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-json",children:'"stryker-config": {\n "ignore-mutations": [\n "linq.First",\n "linq.Sum"\n ]\n}\n'})}),"\n",(0,i.jsxs)(t.blockquote,{children:["\n",(0,i.jsx)(t.p,{children:"Note: this only works for Linq mutations for now, but we plan to bring this functionality to all mutations."}),"\n"]}),"\n",(0,i.jsx)(t.h3,{id:"msbuild-path-option",children:"MsBuild path option"}),"\n",(0,i.jsx)(t.p,{children:"By default Stryker tries to auto-discover MSBuild on your system. However, if Stryker fails to discover the correct MSBuild, you may manually supply the path with this option."}),"\n",(0,i.jsx)(t.p,{children:"Example:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-shell",children:'--msbuild-path "c://MsBuild/MsBuild.exe"\n'})}),"\n",(0,i.jsx)(t.h3,{id:"target-framework",children:"Target framework"}),"\n",(0,i.jsx)(t.p,{children:"If the project targets multiple frameworks, it is now possible to specify the particular framework to build against. If you set a non-existent target, Stryker will build the project against a random one (or the only one if so)."}),"\n",(0,i.jsx)(t.p,{children:"Example:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-json",children:'{\n "stryker-config": {\n "target-framework": "netcoreapp3.1"\n }\n}\n'})}),"\n",(0,i.jsx)(t.h3,{id:"filter-test-cases",children:"Filter test cases"}),"\n",(0,i.jsx)(t.p,{children:"A long-awaited feature has finally found its way
1into Stryker! It is now possible to exclude some test cases. So, for example, if you have long-running integration tests in your unit test project, they can be disabled for Stryker, improving the performance."}),"\n",(0,i.jsx)(t.p,{children:"Example:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-json",children:'{\n "stryker-config": {\n "test-case-filter": "(FullyQualifiedName~UnitTest1&TestCategory=CategoryA)|Priority=1"\n }\n}\n'})}),"\n",(0,i.jsxs)(t.p,{children:["Uses ",(0,i.jsx)(t.code,{children:"dotnet test --filter"})," option syntax, ",(0,i.jsx)(t.a,{href:"https://docs.microsoft.com/en-us/dotnet/core/testing/selective-unit-tests",children:"detailed here"}),"."]}),"\n",(0,i.jsx)(t.h3,{id:"use-source-link-for-dashboard-reporter",children:"Use Source Link for dashboard reporter"}),"\n",(0,i.jsxs)(t.p,{children:["Filling all settings to use the dashboard reporter could be a bit of a hassle. However, thanks to ",(0,i.jsx)(t.a,{href:"https://github.com/dotnet/sourcelink#readme",children:"Source Link"}),", the repository URL and the full version (including the git SHA1) of a project can be included in the produced assembly."]}),"\n",(0,i.jsx)(t.p,{children:"Stryker now uses the information computed by SourceLink to automatically retrieve the project name (github.com/organization/project) and project version, both of which are requirements for the dashboard reporter."}),"\n",(0,i.jsxs)(t.p,{children:["Enable this by adding the following to your ",(0,i.jsx)(t.code,{children:".csproj"}),":"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-xml",children:' <ItemGroup>\n <PackageReference Include="DotNet.ReproducibleBuilds" Version="0.1.66" PrivateAssets="All"/>\n </ItemGroup>\n'})}),"\n",(0,i.jsxs)(t.p,{children:["For more information on SourceLink and ReproducibleBuilds see ",(0,i.jsx)(t.a,{href:"https://github.com/dotnet/sourcelink",children:"SourceLink"})," and ",(0,i.jsx)(t.a,{href:"https://github.com/dotnet/reproducible-builds",children:"Dotnet.ReproducibleBuilds"})]}),"\n",(0,i.jsx)(t.h3,{id:"block-removal-mutations",children:"Block removal mutations"}),"\n",(0,i.jsx)(t.p,{children:'Finally the last missing "common" mutation is added to Stryker.NET! Block removal mutations empty every block statement in your code. This means method bodies or statement bodies (if, while, for). With this mutation Stryker will have improved coverage on your complete codebase. Every method will have at least one mutation and thus should have at least one test.'}),"\n",(0,i.jsx)(t.h2,{id:"-bug-fixes",children:"\u{1F41B} Bug fixes"}),"\n",(0,i.jsx)(t.h3,{id:"no-more-mutated-assembly-on-disk-after-stryker-run",children:"No more mutated assembly on disk after Stryker run"}),"\n",(0,i.jsx)(t.p,{children:"During mutation testing, Stryker replaces your system under test assembly on disk. Up till now, the mutated assembly stayed in place after mutation testing was done. This had some unintended side effects. For example, code coverage results could be incorrect until you rebuild your project, and there was the risk of accidentally releasing/publishing the mutated assembly instead of the original if you did not rebuild your project after mutation testing in your pipelines. We now copy your original assembly before we modify it and place it back after mutation testing. No more rebuild required!"}),"\n",(0,i.jsx)(t.h2,{id:"-team-expansion",children:"\u{1F46A} Team expansion"}),"\n",(0,i.jsxs)(t.p,{children:["We welcome ",(0,i.jsx)(t.a,{href:"https://github.com/dupdob",children:"Cyrille DUPUYDAUBY"})," to the team! They have supported us with feedback, testing, and development since 2018. It was long past due that we officially recognized their contributions to the project!"]}),"\n",(0,i.jsx)(t.h2,{id:"-thank-you",children:"\u{1F389} Thank you"}),"\n",(0,i.jsxs)(t.p,{children:["Special thanks to ",(0,i.jsx)(t.a,{href:"https://github.com/dupdob",children:"Cyrille DUPUYDAUBY"}),", ",(0,i.jsx)(t.a,{href:"https://github.com/psfinaki",children:"Peter Semkin"}),", ",(0,i.jsx)(t.a,{href:"https://github.com/philrowan-mtb",children:"Philip Rowan"}),", ",(0,i.jsx)(t.a,{href:"https://github.com/corentinaltepe",children:"Corentin Altepe"}),", ",(0,i.jsx)(t.a,{href:"https://github.com/0xced",children:"C\xe9dric Luthi"}),", ",(0,i.jsx)(t.a,{href:"https://github.com/grbell-ms",children:"Gregory Bell"}),", ",(0,i.jsx)(t.a,{href:"https://github.com/JohnMcGlynnMSFT",children:"John McGlynn"}),", ",(0,i.jsx)(t.a,{href:"https://github.com/Bforslund",children:"Beatrice Forslund"}),", ",(0,i.jsx)(t.a,{href:"https://github.com/dukedagmor",children:"dukedagmor"})," and anyone else we may have missed for their efforts to make this release happen \u{1F44F} We truly appreciate all the help and feedback we receive!"]})]})}function c(e={}){let{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},42853:function(e,t,n){t.A=n.p+"assets/images/statement-mutation-01ed612b8bd8d4c674020acfb751584e.png"},23191:function(e,t,n){n.d(t,{R:function(){return l},x:function(){return o}});var r=n(92990);let i={},s=r.createContext(i);function l(e){let t=r.useContext(s);return r.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:l(e.components),r.createElement(s.Provider,{value:t},e.children)}},36680:function(e){e.exports=JSON.parse('{"permalink":"/blog/2021-30-10-announcing-stryker-net-1","editUrl":"https://github.com/stryker-mutator/stryker-mutator.github.io/edit/develop/blog/2021-10-30-announcing-stryker-net-1.mdx","source":"@site/blog/2021-10-30-announcing-stryker-net-1.mdx","title":"Announcing Stryker.NET 1.0","description":"We\'re proud to announce the first major release of Stryker.NET: 1.0. It comes with exciting new features and an overhaul of how you interact with the Stryker CLI. With the release of Stryker 1.0, we wanted to create a cohesive and intuitive user experience.","date":"2021-10-30T00:00:00.000Z","tags":[{"inline":true,"label":"stryker.net","permalink":"/blog/tags/stryker-net"},{"inline":true,"label":"release","permalink":"/blog/tags/release"},{"inline":true,"label":"mutation testing","permalink":"/blog/tags/mutation-testing"},{"inline":true,"label":"stryker mutator","permalink":"/blog/tags/stryker-mutator"}
1,{"inline":true,"label":"stryker-js","permalink":"/blog/tags/stryker-js"}],"readingTime":7.84,"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":"2021-30-10-announcing-stryker-net-1","title":"Announcing Stryker.NET 1.0","authors":"richardwerkman","tags":["stryker.net","release","mutation testing","stryker mutator","stryker-js"]},"unlisted":false,"prevItem":{"title":"Announcing StrykerJS v6.0 Beta","permalink":"/blog/announcing-stryker-js-v6-beta"},"nextItem":{"title":"Stryker4s: from 40 minutes to 40 seconds","permalink":"/blog/stryker4s-40-minutes-to-40-seconds"}}')}}]);
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.