рд╕рднреА рдХреЛ рдирдорд╕реНрдХрд╛рд░!
Habr├й рдкрд░ SpecFlow рдХреЗ рдмреЗрд╣рддрд░реАрди рд▓реЗрдЦ рд╣реИрдВред рдореИрдВ рдЗрд╕ рд╡рд┐рд╖рдп рдореЗрдВ рддрд▓реНрд▓реАрди рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдФрд░ рд╕рдорд╛рдирд╛рдВрддрд░ рдореЗрдВ рдкрд░реАрдХреНрд╖рдг рдЪрд▓рд╛рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ, рдЪрд░рдгреЛрдВ рдХреЗ рдмреАрдЪ рдбреЗрдЯрд╛ рдкрд╛рд░рд┐рдд рдХрд░рдирд╛, рд╕рд╣рд╛рдпрдХреЛрдВ рдХреА рд╕рд╣рд╛рдпрддрд╛ рдХрд░рдирд╛, рд░реВрдкрд╛рдВрддрд░рдг, рд╣реБрдХ, рдФрд░ рдбреЗрдЯрд╛ рд╕реНрд░реЛрдд рдХреЗ рд░реВрдк рдореЗрдВ рдЬрд╕рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ред
рд╕рдорд╛рдирд╛рдВрддрд░ рдирд┐рд╖реНрдкрд╛рджрди рдФрд░ рдЪрд░рдгреЛрдВ рдХреЗ рдмреАрдЪ рдбреЗрдЯрд╛ рд╕реНрдерд╛рдирд╛рдВрддрд░рдг
рдЪрд░рдгреЛрдВ рдХреЗ рдмреАрдЪ рдбреЗрдЯрд╛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд
рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП
рдкреНрд░рд▓реЗрдЦрди рдореЗрдВ , рд╣рдо рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЙрджрд╛рд╣рд░рдг рдкрд╛рддреЗ рд╣реИрдВ:
рдпрд╣ рдХреЛрдб рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреБрдВрдЬрд┐рдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред рдЙрдиреНрд╣реЗрдВ рдпрд╛рдж рдФрд░ рдЯрд╛рдЗрдк рдХрд░рдирд╛ рдХрд╛рдлреА рдердХрд╛рдК рд╣реИред
рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рдЖрд╡рд╢реНрдпрдХ рдЧреБрдгреЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рд╕реНрдерд┐рд░ рд╡рд░реНрдЧ рдмрдирд╛рдХрд░ рд╣рд▓ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:
public static class ScenarioData { public static ComplexObject Complex { get => ScenarioContext.Current.Get<ComplexObject>(nameof(Complex)); set => ScenarioContext.Current.Set(value, nameof(Complex)); } }
рдбреЗрдЯрд╛ рд╕реНрдерд╛рдирд╛рдВрддрд░рдг рдЕрдм рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:
рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, рдЬрдм рддрдХ рд╣рдо рдЖрд╡рд╢реНрдпрдХ рдЗрдВрдЬреЗрдХреНрд╢рди рдирд╣реАрдВ рдмрдирд╛рддреЗ рддрдм рддрдХ рд╣рдо рд╕рдорд╛рдирд╛рдВрддрд░ рдореЗрдВ рдкрд░реАрдХреНрд╖рдг рдЪрд▓рд╛рдиреЗ рдкрд░ рдкрд░рд┐рджреГрд╢реНрдпреЛ
рдХрд╛ рдЙрдкрдпреЛрдЧ
рдирд╣реАрдВ рдХрд░ рдкрд╛рдПрдВрдЧреЗ
рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдордиреЗ рдХреБрдЫ рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЛ рд╣рд▓ рдХрд┐рдпрд╛: рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреБрдВрдЬреА рд╕реЗ рдЫреБрдЯрдХрд╛рд░рд╛ рдкрд╛ рд▓рд┐рдпрд╛ рдФрд░ рд╕рдорд╛рдирд╛рдВрддрд░ рдореЗрдВ рдкрд░реАрдХреНрд╖рдг рдЪрд▓рд╛рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдкреНрд░рджрд╛рди рдХреАред рдЬреЛ рд▓реЛрдЧ рдкреНрд░рдпреЛрдЧ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рдЙрдирдХреЗ рд▓рд┐рдП рдореИрдВрдиреЗ рдПрдХ
рдЫреЛрдЯрд╛ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдмрдирд╛рдпрд╛
редрд╕рд╣рд╛рдпрдХ рд╕рд╣рд╛рдпрдХреЛрдВ рдФрд░ рд░реВрдкрд╛рдВрддрд░рдг
рдЕрдЧрд▓реЗ рдЪрд░рдг рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ
When user starts rendering | SourceType | PageOrientation | PageMediaSizeName | | set-01-valid | Landscape | A4 |
рдЕрдХреНрд╕рд░, рдПрдХ рддрд╛рд▓рд┐рдХрд╛ рд╕реЗ рдбреЗрдЯрд╛ рдЗрд╕ рддрд░рд╣ рдШрдЯрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ
[When(@"user starts Rendering")] public async Task WhenUserStartsRendering(Table table) { var sourceType = table.Rows.First()["SourceType"]; var pageOrientation = table.Rows.First()["PageOrientation"]; var pageMediaSizeName = table.Rows.First()["PageMediaSizeName"]; ... }
рд╕рд╣рд╛рдпрдХ рд╕рд╣рд╛рдпрдХреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛
, рдкрд░реАрдХреНрд╖рдг рдбреЗрдЯрд╛ рдкрдврд╝рдирд╛ рдЕрдзрд┐рдХ рд╕реБрд░реБрдЪрд┐рдкреВрд░реНрдг рд▓рдЧрддрд╛ рд╣реИред рд╣рдореЗрдВ рдЙрдЪрд┐рдд рдЧреБрдгреЛрдВ рд╡рд╛рд▓рд╛ рдПрдХ рдореЙрдбрд▓ рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:
public class StartRenderingRequest { public string SourceType { get; set; } public string PageMediaSizeName { get; set; } public string PageOrientation { get; set; } }
рдФрд░ рдЗрд╕реЗ CreateInstance рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ
[When(@"user starts Rendering")] public async Task WhenUserStartsRendering(Table table) { var request = table.CreateInstance<StartRenderingRequest>(); ... }
рд░реВрдкрд╛рдВрддрд░рдг рдХреЗ рд╕рд╛рде, рдкрд░реАрдХреНрд╖рдг рдХрджрдо рдХрд╛ рд╡рд░реНрдгрди рдЖрдЧреЗ рднреА рд╕рд░рд▓ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
рдкрд░рд┐рд╡рд░реНрддрди рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░реЗрдВ:
[Binding] public class Transforms { [StepArgumentTransformation] public StartRenderingRequest StartRenderingRequestTransform(Table table) { return table.CreateInstance<StartRenderingRequest>(); } }
рдЕрдм рд╣рдо рд╕реНрдЯреЗрдк рдореЗрдВ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд░реВрдк рдореЗрдВ рд╡рд╛рдВрдЫрд┐рдд рдкреНрд░рдХрд╛рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
[When(@"user starts Rendering")] public async Task WhenUserStartsRendering(StartRenderingRequest request) {
рдЙрди рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдЬреЛ рдкреНрд░рдпреЛрдЧ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ -
рдПрдХ рд╣реА рдкрд░рд┐рдпреЛрдЬрдирд╛редрд╣реБрдХ рдФрд░ Json рдкрд░реАрдХреНрд╖рдг рдбреЗрдЯрд╛ рдХреЗ рдПрдХ рд╕реНрд░реЛрдд рдХреЗ рд░реВрдк рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛
SpecFlow рдЯреЗрдмрд▓ рд╕рд░рд▓ рдкрд░реАрдХреНрд╖рдг рдбреЗрдЯрд╛ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╕реЗ рдЕрдзрд┐рдХ рд╣реИрдВред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдорд╛рдкрджрдВрдбреЛрдВ рдФрд░ / рдпрд╛ рдПрдХ рдЬрдЯрд┐рд▓ рдбреЗрдЯрд╛ рд╕рдВрд░рдЪрдирд╛ рдХреЗ рд╕рд╛рде рдкрд░реАрдХреНрд╖рдг рдкрд░рд┐рджреГрд╢реНрдп рд╣реИрдВред рдЗрд╕ рддрд░рд╣ рдХреЗ рдкрд░реАрдХреНрд╖рдг рдбреЗрдЯрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреА рдкрдардиреАрдпрддрд╛ рдХреЛ рдмрдирд╛рдП рд░рдЦрддреЗ рд╣реБрдП, рд╣рдореЗрдВ
рд╣реБрдХ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рд╣рдо Json рдлрд╝рд╛рдЗрд▓ рд╕реЗ рдЖрд╡рд╢реНрдпрдХ рдбреЗрдЯрд╛ рдХреЛ рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП [рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ [рдПрд╕рд╕реЗрдирд╛рд░рд┐рдпреЛ] рд╣реБрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╕реНрддрд░ рдкрд░ рд╡рд┐рд╢реЗрд╖
рдЯреИрдЧ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░реЗрдВ
@jsonDataSource @jsonDataSourcePath:DataSource\FooResponse.json Scenario: Validate Foo functionality Given user has access to the Application Service When user invokes Foo functionality | FooRequestValue | | input | Then Foo functionality should complete successfully
рдФрд░ рд╣реБрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рддрд░реНрдХ рдЬреЛрдбрд╝реЗрдВ:
[BeforeScenario("jsonDataSource")] public void BeforeScenario() { var tags = ScenarioContext.ScenarioInfo.Tags; var jsonDataSourcePathTag = tags.Single(i => i.StartsWith(TagJsonDataSourcePath)); var jsonDataSourceRelativePath = jsonDataSourcePathTag.Split(':')[1]; var jsonDataSourcePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, jsonDataSourceRelativePath); var jsonRaw = File.ReadAllText(jsonDataSourcePath); ScenarioData.JsonDataSource = jsonRaw; }
рдпрд╣ рдХреЛрдб json рдлрд╝рд╛рдЗрд▓ (рдлрд╝рд╛рдЗрд▓ рдХреЗ рд╕рд╛рдкреЗрдХреНрд╖ рдкрде) рдХреА рд╕рд╛рдордЧреНрд░реА рдХреЛ рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдЪрд░ рдореЗрдВ рдШрдЯрд╛рддрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдбреЗрдЯрд╛ (рдкрд░рд┐рджреГрд╢реНрдпреЛ.JsonDataSource) рдореЗрдВ рд╕рд╣реЗрдЬрддрд╛ рд╣реИред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдо рдЗрд╕ рдбреЗрдЯрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬрд╣рд╛рдВ рдЖрд╡рд╢реНрдпрдХ рд╣реЛ
[Then(@"Foo functionality should complete successfully")] public void ThenFooFunctionalityShouldCompleteSuccessfully() { var actual = ScenarioData.FooResponse; var expected = JsonConvert.DeserializeObject<FooResponse>(ScenarioData.JsonDataSource); actual.FooResponseValue.Should().Be(expected.FooResponseValue); }
рдЪреВрдВрдХрд┐ Json рдореЗрдВ рдмрд╣реБрдд рдЕрдзрд┐рдХ рдбреЗрдЯрд╛ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рдЯреЗрд╕реНрдЯ рдбреЗрдЯрд╛ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рдирд╛ рдЯреИрдЧ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рднреА рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЬреЛ рд░реБрдЪрд┐ рд░рдЦрддреЗ рд╣реИрдВ рд╡реЗ рдЙрд╕реА
рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рдПрдХ рдЙрджрд╛рд╣рд░рдг рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ
редрд╕рдВрджрд░реНрдн
1.
рдХрдХрдбрд╝реА2.
рдШреЗрд░рдХрд┐рди3.
SpecFlow рдкреНрд░рд▓реЗрдЦрди4.
SpecFlow Wiki5.
рдирд┐рд╖реНрдкрд╛рджрди рдпреЛрдЧреНрдп рд╡рд┐рдирд┐рд░реНрджреЗрд╢: SpecFlow A to Z6.
рдбреЗрдЯрд╛ рдЪрд╛рд▓рд┐рдд рдкрд░реАрдХреНрд╖рдг рдФрд░ SpecFlow