/// <summary> /// 操作を実行する /// </summary> /// <param name="catalog">ユースケース</param> override protected void DoOperate(UseCaseCatalog catalog) { // シナリオごとにファイル生成 foreach (var scenarioSet in catalog.ScenarioSets) { var fileName = string.Format("{0}-テストスイート-{1}.csv", catalog.Title, scenarioSet.Title); var scenarioPath = Path.Combine(OutputDirectoryPath, fileName); Console.Error.WriteLine(Resources.Resources.Message_Format_WriteFileTo_TestSuiteCsv_ScenarioSet, scenarioPath); using (var writer = new StreamWriter(fileName)) { // ヘッダー出力 writer.WriteLine(string.Join(",", headers)); foreach (var scenario in scenarioSet.Scenarios) { // シナリオ出力 var actionNo = 1; writer.WriteLine(string.Join(",", MakeTestCaseFirstActionValues(scenario).Select(value => FormatForCsvFields(value.ToString())))); foreach (var action in scenario.Actions.Skip(1)) { ++actionNo; writer.WriteLine(string.Join(",", MakeTestCaseFollowingActionValues(actionNo, action).Select(value => FormatForCsvFields(value.ToString())))); } } } } }
/// <summary> /// 変換結果を作成する /// </summary> /// <param name="catalog">ユースケースカタログ</param> private void CreateTranslation(UseCaseCatalog catalog) { var useCaseCatalogTemplate = Resources.Resources.ユースケースカタログテンプレート; if (string.IsNullOrWhiteSpace(UseCaseCatalogTemplateFilePath) == false) { using (var reader = new StreamReader(UseCaseCatalogTemplateFilePath)) { useCaseCatalogTemplate = reader.ReadToEnd(); } } var useCaseScenarioSetTemplate = Resources.Resources.ユースケースシナリオセットテンプレート; if (string.IsNullOrWhiteSpace(UseCaseScenarioSetTemplateFilePath) == false) { using (var reader = new StreamReader(UseCaseScenarioSetTemplateFilePath)) { useCaseScenarioSetTemplate = reader.ReadToEnd(); } } InitializeRazorEngineTemplate(useCaseCatalogTemplate, useCaseScenarioSetTemplate); var targetDirPath = OutputDirectoryPath; CreateUseCaseCatalog(catalog); foreach (var scenarioSet in catalog.ScenarioSets) { CreateUseCaseScenarioSet(scenarioSet); } }
// // クラスメソッド // /// <summary> /// 変換結果を指定ディレクトリに作成する /// </summary> /// <param name="catalog">対象ユースケースカタログ</param> /// <param name="outputDirectoryPath">出力ディレクトリ</param> public static void CreateConvertedMarkdownTo(UseCaseCatalog catalog, string outputDirectoryPath) { var parameters = new Dictionary <string, object> { { PARAMETER_OUTPUT, outputDirectoryPath } }; var converter = new MarkdownConverter(parameters); converter.CreateTranslation(catalog); }
/// <summary> /// ユースケースカタログを出力する /// </summary> /// <param name="catalog">ユースケースカタログ</param> private void CreateUseCaseCatalog(UseCaseCatalog catalog) { Contract.Requires(catalog != null); var outputFilePath = Path.Combine(OutputDirectoryPath, Path.ChangeExtension(catalog.FileName, ".md")); Console.Error.WriteLine(Resources.Resources.Message_Format_WriteFileTo_UseCaseCatalog, outputFilePath); using (var writer = new StreamWriter(outputFilePath)) { writer.Write(razorEngineService.Run("UseCaseCatalogTemplateKey", typeof(UseCaseCatalog), catalog)); } }
/// <summary> /// 操作を実行する /// </summary> /// <param name="catalog">ユースケース</param> protected override void DoOperate(UseCaseCatalog catalog) { ReportHelp(); }
/// <summary> /// 操作を実行する /// </summary> /// <param name="catalog">ユースケース</param> protected override void DoOperate(UseCaseCatalog catalog) { CreateTranslation(catalog); }
/// <summary> /// 操作を実行する /// </summary> /// <param name="catalog">ユースケース</param> protected abstract void DoOperate(UseCaseCatalog catalog);
/// <summary> /// ユースケースシナリオの応答コンテントを作成する /// </summary> /// <param name="useCaseScenarioDirPath">ユースケースシナリオファイルの存在するディレクトリのパス</param> /// <param name="catalogFileName">ユースケースカタログのファイル名</param> /// <param name="catalog">ユースケースカタログ</param> /// <returns>応答コンテントインスタンス</returns> private static MultipartContent CreateUseCaseScenarioResponseContent(string useCaseScenarioDirPath, string catalogFileName, UseCaseCatalog catalog) { Contract.Requires(string.IsNullOrWhiteSpace(useCaseScenarioDirPath) == false && Directory.Exists(useCaseScenarioDirPath)); Contract.Requires(string.IsNullOrWhiteSpace(catalogFileName) == false); Contract.Requires(catalog != null); Contract.Ensures(Contract.Result <MultipartContent>() != null); var fileNames = new[] { Path.GetFileName(catalog.FileName), }.Concat(catalog.ScenarioSets.Select(scenarioSet => scenarioSet.FileName)); var responseContent = new MultipartContent("mixed", "BOUNDARY"); foreach (var file in fileNames) { var markdownFile = Path.ChangeExtension(file, ".md"); ByteArrayContent markdownContent; using (var outputStream = new FileStream(Path.Combine(useCaseScenarioDirPath, markdownFile), FileMode.Open, FileAccess.Read)) { using (var reader = new StreamReader(outputStream)) { markdownContent = new ByteArrayContent(Encoding.UTF8.GetBytes(reader.ReadToEnd())); markdownContent.Headers.ContentType = new MediaTypeHeaderValue("text/plain") { CharSet = "UTF-8", }; markdownContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = (file == Path.GetFileName(catalog.FileName) ? Path.ChangeExtension(catalogFileName, ".md") : markdownFile), }; } } responseContent.Add(markdownContent); } return(responseContent); }
/// <summary> /// 操作を実行する /// </summary> /// <param name="catalog">ユースケース</param> override protected void DoOperate(UseCaseCatalog catalog) { Console.Error.WriteLine(Resources.Resources.Message_Format_WriteFileTo_TestSuiteExcel, CreateExcelTestSuiteTo(catalog, OutputDirectoryPath, templateFilePath)); }
// // クラスメソッド // /// <summary> /// Excelテストスイートを指定ディレクトリに作成する /// </summary> /// <param name="catalog">対象ユースケースカタログ</param> /// <param name="outputDirectoryPath">出力ディレクトリ</param> /// <param name="templateFilePath">テンプレートのパス</param> /// <returns>出力ファイルの完全パス</returns> public static string CreateExcelTestSuiteTo(UseCaseCatalog catalog, string outputDirectoryPath, string templateFilePath) { Contract.Requires(catalog != null); Contract.Requires(string.IsNullOrWhiteSpace(outputDirectoryPath) == false && Directory.Exists(outputDirectoryPath)); Contract.Ensures(string.IsNullOrWhiteSpace(Contract.Result <string>()) == false && File.Exists(Contract.Result <string>())); string outputFilePath = string.Empty; using (Stream stream = (string.IsNullOrWhiteSpace(templateFilePath) == false ? new FileStream(templateFilePath, FileMode.Open, FileAccess.Read) as Stream : new MemoryStream(Resources.Resources.テストスイートテンプレート) as Stream)) { using (var template = new XLWorkbook(stream, XLEventTracking.Disabled)) { var summarySheet = template.Worksheet(1); summarySheet.Cell(1, 1).SetValue(string.Format("{0} テストスイート", catalog.Title)); summarySheet.Cell(2, 1).SetValue(string.Format("最終更新日時: {0:yyyy-MM-dd}", catalog.LastUpdateTime)); var testCaseTemplateSheet = template.Worksheet(2); var tooLongTitles = catalog.ScenarioSets.Select(scenarioSet => scenarioSet.Title).Where(title => 31 <= title.Length); if (tooLongTitles.Any()) { throw new ApplicationException(string.Format(Resources.Resources.Exception_Format_TooLongScenarioSetTitle, string.Join("\n\t", tooLongTitles))); } foreach (var scenarioSet in catalog.ScenarioSets) { testCaseTemplateSheet.CopyTo(scenarioSet.Title); var testCaseSetSheet = template.Worksheet(template.Worksheets.Count()); testCaseSetSheet.Cell(1, 2).SetValue(scenarioSet.Title); if (scenarioSet.Summary is string) { var summaryLines = Regex.Replace(scenarioSet.Summary, "\\s*\\\\n\\s*", "\n").Split('\n').Select(line => line.Trim()); testCaseSetSheet.Cell(2, 2).SetValue(1 < summaryLines.Count() ? string.Join(Environment.NewLine, summaryLines) : scenarioSet.Summary); } else { testCaseSetSheet.Cell(2, 2).SetValue(ConvertCollectionValue(scenarioSet.Summary)); } var templateRow = testCaseSetSheet.Row(6); var testCaseRow = templateRow; foreach (var scenario in scenarioSet.Scenarios) { var firstActionValues = MakeTestCaseFirstActionValues(scenario).ToList(); var actionNo = 1; testCaseRow = testCaseRow.InsertRowsBelow(1).First(); for (var cellIndex = 1; cellIndex <= firstActionValues.Count(); ++cellIndex) { testCaseRow.Cell(cellIndex).SetValue(firstActionValues[cellIndex - 1]); } foreach (var action in scenario.Actions.Skip(1)) { ++actionNo; var actionValues = MakeTestCaseFollowingActionValues(actionNo, action).ToList(); testCaseRow = testCaseRow.InsertRowsBelow(1).First(); for (var cellIndex = 1; cellIndex <= actionValues.Count(); ++cellIndex) { testCaseRow.Cell(cellIndex).SetValue(actionValues[cellIndex - 1]); } } // 最後に空行を入れる testCaseRow = testCaseRow.InsertRowsBelow(1).First(); } testCaseRow.Delete(); templateRow.Delete(); } template.Worksheet(2).Delete(); outputFilePath = Path.Combine(outputDirectoryPath, string.Format(Resources.Resources.FileName_Format_TestSuiteExcel, catalog.Title)); template.SaveAs(outputFilePath); } } return(outputFilePath); }
// // クラスメソッド // /// <summary> /// 結果を検証する /// </summary> /// <param name="path">出力ファイルパス</param> /// <param name="catalog">ユースケースカタログ</param> /// <param name="op">テストスイートビルダー</param> private static void AssertResult(string path, UseCaseCatalog catalog, ExcelTestSuiteBuilder op) { op.Operate(); var fileName = string.Format("{0}-テストスイート.xlsx", catalog.Title); var testSuitePath = Path.Combine(path, fileName); Assert.IsTrue(File.Exists(testSuitePath)); try { using (var testSuite = new XLWorkbook(testSuitePath)) { Assert.IsTrue(2 <= testSuite.Worksheets.Count()); var summarySheet = testSuite.Worksheets.First(); Assert.IsTrue(summarySheet.Cell(1, 1).Value.ToString() == string.Format("{0} テストスイート", catalog.Title)); Assert.IsTrue(summarySheet.Cell(2, 1).Value.ToString() == string.Format("最終更新日時: {0:yyyy-MM-dd}", catalog.LastUpdateTime)); var scenarioSetIndex = 0; foreach (var testCaseSetSheet in testSuite.Worksheets.Skip(1)) { var scenarioSet = catalog.ScenarioSets.Skip(scenarioSetIndex).First(); ++scenarioSetIndex; Assert.IsTrue(testCaseSetSheet.Cell(1, 2).Value.ToString() == scenarioSet.Title); Assert.IsTrue(testCaseSetSheet.Cell(2, 2).Value.ToString() == scenarioSet.Summary); var scenarioIndex = 0; var actionIndex = 0; UseCaseScenario scenario = null; UseCaseScenarioAction action = null; var rowIndex = 6; while ((scenarioIndex + 1) < scenarioSet.Scenarios.Count() || (actionIndex + 1) < scenario.Actions.Count()) { var row = testCaseSetSheet.Row(rowIndex); ++rowIndex; if (row.CellCount() == 0 || row.Cells().All(cell => string.IsNullOrWhiteSpace(cell.Value.ToString()))) { continue; } if (string.IsNullOrWhiteSpace(row.Cell(1).Value.ToString()) == false) { scenario = scenarioSet.Scenarios.Skip(scenarioIndex).First(); ++scenarioIndex; actionIndex = 0; Assert.IsTrue(row.Cell(1).Value.ToString() == scenario.Title); Assert.IsTrue(row.Cell(2).Value.ToString() == scenario.Summary); var testCasePreconditions = row.Cell(3).Value.ToString(); foreach (var precondition in scenario.Preconditions) { Assert.IsTrue(testCasePreconditions.Contains(precondition)); } } action = scenario.Actions.Skip(actionIndex).First(); ++actionIndex; Assert.IsTrue(row.Cell(4).Value.ToString() == actionIndex.ToString()); Assert.IsTrue(row.Cell(5).Value.ToString() == action.Action); var testCaseResults = row.Cell(6).Value.ToString(); foreach (var result in action.Results) { Assert.IsTrue(testCaseResults.Contains(result)); } Assert.IsTrue(row.Cell(7).Value.ToString() == "手動"); Assert.IsTrue(string.IsNullOrWhiteSpace(row.Cell(8).Value.ToString())); Assert.IsTrue(string.IsNullOrWhiteSpace(row.Cell(9).Value.ToString())); } } } } finally { try { File.Delete(testSuitePath); } catch { // Do nothing. } } }
/// <summary> /// ユースケースカタログを読みこむ /// </summary> /// <param name="reader">読みこみ元</param> /// <param name="catalogFileName">ユースケースカタログファイル名</param> /// <param name="catalogLastUpdateTime">ユースケースカタログの最終更新日時</param> /// <returns>インスタンス</returns> public UseCaseCatalog ReadFrom(TextReader reader, string catalogFileName, DateTime catalogLastUpdateTime) { Contract.Requires(reader != null); Contract.Ensures(Contract.Result <UseCaseCatalog>() != null); UseCaseCatalog catalog = null; var lastUpdateTime = catalogLastUpdateTime; var deserializer = new DeserializerBuilder() .WithNamingConvention(new CamelCaseNamingConvention()) .WithNodeTypeResolver(new CustomNodeTypeResolver()) .IgnoreUnmatchedProperties() .Build(); var asYaml = deserializer.Deserialize <ValueOverwriteDisallowDictionary <object, object> >(reader); Contract.Assert(asYaml != null); if (asYaml.ContainsKey("ユースケースシナリオカタログ")) { // シナリオセットを読みこむ var scenarioSet = new List <KeyValuePair <string, Dictionary <object, object> > >(); foreach (var scenarioFilePath in asYaml["シナリオセット"] as IEnumerable <object> ) { var path = scenarioFilePath as string; if (path == null) { throw new ArgumentOutOfRangeException(Resources.Resources.Exception_InvalidScenarioSetFileSpecification); } path = Utilities.TryToNormalizeFilePath(path); var exists = File.Exists(path); if (exists == false && string.IsNullOrWhiteSpace(referenceDirectory) == false) { path = Utilities.TryToNormalizeFilePath(Path.Combine(referenceDirectory, path)); exists = File.Exists(path); } if (exists == false) { throw new FileNotFoundException(Resources.Resources.Exception_ScenarioSetFileNotFound, scenarioFilePath as string); } var scenarioSetLastUpdateTime = File.GetLastWriteTime(path); if (lastUpdateTime < scenarioSetLastUpdateTime) { lastUpdateTime = scenarioSetLastUpdateTime; } try { using (var scenarioReader = new StreamReader(path)) { var scenarioSetAsYaml = deserializer.Deserialize <ValueOverwriteDisallowDictionary <object, object> >(scenarioReader); Contract.Assert(scenarioSetAsYaml != null); scenarioSet.Add(new KeyValuePair <string, Dictionary <object, object> >(Path.GetFileName(path), scenarioSetAsYaml.AsDictionary)); } } catch (YamlException e) { throw new ApplicationException(string.Format(Resources.Resources.Exception_Format_InvalidScenarioSetFileFormat, path, e.Message), e); } } asYaml.Remove("シナリオセット"); var title = asYaml["ユースケースシナリオカタログ"] as string; asYaml.Remove("ユースケースシナリオカタログ"); var updateHistory = new List <UseCaseUpdateInfo>(); if (asYaml.ContainsKey("更新履歴")) { updateHistory.AddRange((asYaml["更新履歴"] as ValueOverwriteDisallowDictionary <object, object>).AsDictionary.Select(history => UseCaseUpdateInfo.CreateInstance(history))); asYaml.Remove("更新履歴"); } catalog = new UseCaseCatalog(catalogFileName, lastUpdateTime, title, scenarioSet, updateHistory, asYaml.AsDictionary); } else if (asYaml.ContainsKey("ユースケースシナリオセット")) { // 自身がシナリオセット catalog = new UseCaseCatalog(new List <KeyValuePair <string, Dictionary <object, object> > > { new KeyValuePair <string, Dictionary <object, object> >(catalogFileName, asYaml.AsDictionary) }); } return(catalog); }