{"action":"created","issue":{"url":"https://api.github.com/repos/AutoFixture/AutoFixture/issues/430","labels_url":"https://api.github.com/repos/AutoFixture/AutoFixture/issues/430/labels{/name}","comments_url":"https://api.github.com/repos/AutoFixture/AutoFixture/issues/430/comments","events_url":"https://api.github.com/repos/AutoFixture/AutoFixture/issues/430/events","html_url":"https://github.com/AutoFixture/AutoFixture/pull/430","id":98457829,"number":430,"title":"Substitute attribute, ","user":{"login":"olegsych","id":8355091,"avatar_url":"https://avatars.githubusercontent.com/u/8355091?v=3","gravatar_id":"","url":"https://api.github.com/users/olegsych","html_url":"https://github.com/olegsych","followers_url":"https://api.github.com/users/olegsych/followers","following_url":"https://api.github.com/users/olegsych/following{/other_user}","gists_url":"https://api.github.com/users/olegsych/gists{/gist_id}","starred_url":"https://api.github.com/users/olegsych/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/olegsych/subscriptions","organizations_url":"https://api.github.com/users/olegsych/orgs","repos_url":"https://api.github.com/users/olegsych/repos","events_url":"https://api.github.com/users/olegsych/events{/privacy}","received_events_url":"https://api.github.com/users/olegsych/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":5,"created_at":"2015-07-31T19:41:00Z","updated_at":"2015-09-02T14:40:36Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/AutoFixture/AutoFixture/pulls/430","html_url":"https://github.com/AutoFixture/AutoFixture/pull/430","diff_url":"https://github.com/AutoFixture/AutoFixture/pull/430.diff","patch_url":"https://github.com/AutoFixture/AutoFixture/pull/430.patch"},"body":"The proposed `SubstituteAttribute` enables changing the default fixture behavior and forcing creation of concrete type substitutes for individual test parameters. The implementation follows the pattern established by the `AutoFixture` for data annotation attributes, such as `[Range]`, `[RegularExpression]` and `[StringLength]`.\r\n\r\nThe idea was previously discussed in #132 and submitted in #421. The proposed implementation does _not_ include the previously rejected `AttributeRelay<T>` refactoring #424.\r\n\r\nHere are samples that illustrate this attribute's use:\r\n\r\n```C#\r\n[Theory, AutoDataWithAutoSubstituteCustomization]\r\npublic void ConcreteTypesAreSubstitutedWhenParameterIsMarkedWithSubstituteAttribute(\r\n    [Substitute]ConcreteType t, object obj)\r\n{\r\n    t.VirtualMethod(obj);\r\n    t.Received().VirtualMethod(obj);\r\n}\r\n\r\n[Theory, AutoDataWithAutoSubstituteCustomization]\r\npublic void SubstituteAttributeAppliesToSingleParameterAndNotItsEntireType(\r\n    [Substitute]ConcreteType t1, ConcreteType t2, object obj)\r\n{\r\n    t2.VirtualMethod(obj);\r\n    Assert.Throws<NotASubstituteException>(() => t2.Received().VirtualMethod(obj));\r\n}\r\n```\r\n\r\nApplying the `SubstituteAttribute` to a parameter of a concrete type fails the test, such as the one in example below, _before_ running it.\r\n\r\n```C#\r\n[Theory, AutoDataWithAutoSubstituteCustomization]\r\npublic void AttemptingToSubstituteSealedTypeFailsTestBeforeItStarts(\r\n    [Substitute]SealedType t, object obj)\r\n{\r\n}\r\n```\r\n\r\nApplying the `SubstituteAttribute` in a method with a regular `AutoDataAttribute` results in an obscure failure within the test itself because the attribute has no behavior and requires the `AutoSubstituteCustomization` to be applied to the test's `Fixture`. Below is a sample that illustrates the problem. A separate pull request #418 was started earlier to enable addressing it.\r\n\r\n```C#\r\n[Theory, AutoData]\r\npublic void SubstituteAttributeShouldWorkWithPlainAutoDataAttribute(\r\n    [Substitute]ConcreteType t, object obj)\r\n{\r\n    t.VirtualMethod(obj);\r\n    // The following line throws NotASubstituteExeption, which is confusing because the\r\n    // Substitute attribute is clearly used.\r\n    t.Received().VirtualMethod(obj);\r\n}\r\n```\r\n\r\n### Changes in AutoFixture.NSubstitute\r\n- Implement `SubstituteAttribute`.\r\n- Implement `SubstituteRequest` used to request a substitute of a given type.\r\n- Implement `SubstituteRequestHandler` to handle substitute requests.\r\n- Implement `SubstituteAttributeRelay` to convert requests for parameters, properties and fields marked with the `SubstituteAttribute` to substitute requests of their respective types.\r\n- Implement `SubstituteRelay` to convert requests for abstract types and interfaces to requests for substitutes.\r\n- Change existing `AutoNSubstituteCustomization` and `AutoConfiguredNSubstituteCustomization` to use the new components instead of the existing `NSubstituteBuilder`. "},"comment":{"url":"https://api.github.com/repos/AutoFixture/AutoFixture/issues/comments/137107055","html_url":"https://github.com/AutoFixture/AutoFixture/pull/430#issuecomment-137107055","issue_url":"https://api.github.com/repos/AutoFixture/AutoFixture/issues/430","id":137107055,"user":{"login":"olegsych","id":8355091,"avatar_url":"https://avatars.githubusercontent.com/u/8355091?v=3","gravatar_id":"","url":"https://api.github.com/users/olegsych","html_url":"https://github.com/olegsych","followers_url":"https://api.github.com/users/olegsych/followers","following_url":"https://api.github.com/users/olegsych/following{/other_user}","gists_url":"https://api.github.com/users/olegsych/gists{/gist_id}","starred_url":"https://api.github.com/users/olegsych/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/olegsych/subscriptions","organizations_url":"https://api.github.com/users/olegsych/orgs","repos_url":"https://api.github.com/users/olegsych/repos","events_url":"https://api.github.com/users/olegsych/events{/privacy}","received_events_url":"https://api.github.com/users/olegsych/received_events","type":"User","site_admin":false},"created_at":"2015-09-02T14:40:36Z","updated_at":"2015-09-02T14:40:36Z","body":"I have implemented the changes we agreed on (remove `AutoSubstituteCustomization`, rename `SubstituteBuilder` to `SubstituteRequestHandler` and changed the existing `AutoNSubstituteCustomization` and `AutoConfiguredNSubstituteCustomization` to use the new components instead of the existing `NSubstituteBuilder`). Please take a look."}}