private static string ReplaceInterfaceTokens(string template, InjectableType injectableType) { return(template .Replace("$InterfaceName$", injectableType.TypeName) .Replace("$InterfaceNameBase$", injectableType.TypeBaseName) .Replace("$InterfaceType$", injectableType.ToString()) .Replace("$InterfaceMockName$", injectableType.MockName)); }
private static void WriteExplicitConstructor(StringBuilder builder, TestGenerationContext context, string currentIndent) { builder.Append($"new {context.ClassName}"); if (context.ConstructorTypes.Count > 0) { builder.AppendLine("("); for (int i = 0; i < context.ConstructorTypes.Count; i++) { string mockReferenceStatement; InjectableType constructorType = context.ConstructorTypes[i]; if (constructorType == null) { mockReferenceStatement = "TODO"; } else { string template = StaticBoilerplateSettings.GetTemplate(context.MockFramework, TemplateType.MockObjectReference); mockReferenceStatement = template .Replace("$InterfaceName$", constructorType.TypeName) .Replace("$InterfaceNameBase$", constructorType.TypeBaseName); } builder.Append($"{currentIndent} {mockReferenceStatement}"); if (i < context.ConstructorTypes.Count - 1) { builder.AppendLine(","); } } builder.Append(")"); } else if (context.Properties.Count == 0) { builder.Append("()"); } if (context.Properties.Count > 0) { builder.AppendLine(); builder.AppendLine("{"); foreach (InjectableProperty property in context.Properties) { string template = StaticBoilerplateSettings.GetTemplate(context.MockFramework, TemplateType.MockObjectReference); string mockReferenceStatement = template .Replace("$InterfaceName$", property.TypeName) .Replace("$InterfaceNameBase$", property.TypeBaseName); builder.AppendLine($"{property.Name} = {mockReferenceStatement},"); } builder.Append(@"}"); } }
// Works for both field declarations and initializations. private static void WriteFieldLines(StringBuilder builder, TestGenerationContext context, string template) { for (int i = 0; i < context.InjectedTypes.Count; i++) { InjectableType injectedType = context.InjectedTypes[i]; string line = ReplaceInterfaceTokens(template, injectedType); builder.Append(line); if (i < context.InjectedTypes.Count - 1) { builder.AppendLine(); } } }
// Works for both field declarations and initializations. private static void WriteFieldLines(StringBuilder builder, TestGenerationContext context, string template) { for (int i = 0; i < context.InjectedTypes.Count; i++) { InjectableType injectedType = context.InjectedTypes[i]; string line = template .Replace("$InterfaceName$", injectedType.TypeName) .Replace("$InterfaceNameBase$", injectedType.TypeBaseName); builder.Append(line); if (i < context.InjectedTypes.Count - 1) { builder.AppendLine(); } } }
private static InjectableType CreateInjectableType(SyntaxNode node, SemanticModel semanticModel, SymbolInfo?symbolInfo = null) { switch (node.Kind()) { case SyntaxKind.IdentifierName: if (symbolInfo == null) { symbolInfo = semanticModel.GetSymbolInfo(node); } return(new InjectableType(symbolInfo.Value.Symbol.Name, symbolInfo.Value.Symbol.ContainingNamespace.ToString())); case SyntaxKind.GenericName: if (symbolInfo == null) { symbolInfo = semanticModel.GetSymbolInfo(node); } var injectableType = new InjectableType(symbolInfo.Value.Symbol.Name, symbolInfo.Value.Symbol.ContainingNamespace.ToString()); SyntaxNode typeArgumentNode = node.ChildNodes().FirstOrDefault(n => n.Kind() == SyntaxKind.TypeArgumentList); if (typeArgumentNode == null) { throw new ArgumentException("Could not find type argument node for GenericName node."); } foreach (SyntaxNode genericArgumentNode in typeArgumentNode.ChildNodes()) { injectableType.GenericTypeArguments.Add(CreateInjectableType(genericArgumentNode, semanticModel)); } return(injectableType); case SyntaxKind.PredefinedType: default: return(new InjectableType(node.ToString(), null)); } }
private string GenerateUnitTestContentsOld( string unitTestNamespace, string className, string classNamespace, IList <InjectableProperty> properties, IList <InjectableType> constructorTypes) { TestFramework testFramework = Utilities.FindTestFramework(this.SelectedProject.Project); MockFramework mockFramework = Utilities.FindMockFramework(this.SelectedProject.Project); if (mockFramework == MockFramework.Unknown) { mockFramework = MockFramework.Moq; } string pascalCaseShortClassName = null; foreach (string suffix in ClassSuffixes) { if (className.EndsWith(suffix)) { pascalCaseShortClassName = suffix; break; } } if (pascalCaseShortClassName == null) { pascalCaseShortClassName = className; } string classVariableName = pascalCaseShortClassName.Substring(0, 1).ToLowerInvariant() + pascalCaseShortClassName.Substring(1); List <InjectableType> injectedTypes = new List <InjectableType>(properties); injectedTypes.AddRange(constructorTypes.Where(t => t != null)); var mockFields = new List <MockField>(); foreach (InjectableType injectedType in injectedTypes) { mockFields.Add( new MockField( mockFramework == MockFramework.SimpleStubs ? "stub" + injectedType.TypeBaseName : "mock" + injectedType.TypeBaseName, mockFramework == MockFramework.SimpleStubs ? "Stub" + injectedType.TypeName : injectedType.TypeName)); } List <string> namespaces = new List <string>(); namespaces.AddRange(MockFrameworkAbstraction.GetUsings(mockFramework)); namespaces.Add(TestFrameworkAbstraction.GetUsing(testFramework)); namespaces.Add(classNamespace); namespaces.AddRange(injectedTypes.Select(t => t.TypeNamespace)); namespaces = namespaces.Distinct().ToList(); namespaces.Sort(StringComparer.Ordinal); StringBuilder builder = new StringBuilder(); foreach (string ns in namespaces) { builder.AppendLine($"using {ns};"); } builder.Append( Environment.NewLine + "namespace "); builder.Append(unitTestNamespace); builder.Append( Environment.NewLine + "{" + Environment.NewLine + $"[{TestFrameworkAbstraction.GetTestClassAttribute(testFramework)}]" + Environment.NewLine + "public class "); builder.Append(className); builder.Append( "Tests" + Environment.NewLine + "{" + Environment.NewLine); if (mockFramework == MockFramework.Moq) { builder.Append("private MockRepository mockRepository;" + Environment.NewLine); if (mockFields.Count > 0) { builder.AppendLine(); } } foreach (MockField field in mockFields) { if (mockFramework == MockFramework.SimpleStubs) { builder.AppendLine($"private {field.TypeName} {field.Name};"); } else { builder.AppendLine($"private Mock<{field.TypeName}> {field.Name};"); } } builder.Append( Environment.NewLine + $"[{TestFrameworkAbstraction.GetTestInitializeAttribute(testFramework)}]" + Environment.NewLine + "public void TestInitialize()" + Environment.NewLine + "{" + Environment.NewLine); if (mockFramework == MockFramework.Moq) { builder.AppendLine("this.mockRepository = new MockRepository(MockBehavior.Strict);"); if (mockFields.Count > 0) { builder.AppendLine(); } } foreach (MockField field in mockFields) { string fieldCreationStatement; if (mockFramework == MockFramework.SimpleStubs) { fieldCreationStatement = $"new {field.TypeName}()"; } else { fieldCreationStatement = $"this.mockRepository.Create<{field.TypeName}>()"; } builder.AppendLine($"this.{field.Name} = {fieldCreationStatement};"); } builder.Append( "}" + Environment.NewLine + Environment.NewLine); if (mockFramework == MockFramework.Moq) { builder.Append( $"[{TestFrameworkAbstraction.GetTestCleanupAttribute(testFramework)}]" + Environment.NewLine + "public void TestCleanup()" + Environment.NewLine + "{" + Environment.NewLine + "this.mockRepository.VerifyAll();" + Environment.NewLine + "}" + Environment.NewLine + Environment.NewLine); } builder.Append( $"[{TestFrameworkAbstraction.GetTestMethodAttribute(testFramework)}]" + Environment.NewLine + "public void TestMethod1()" + Environment.NewLine + "{" + Environment.NewLine + "" + Environment.NewLine + "" + Environment.NewLine); builder.AppendLine($"{className} {classVariableName} = this.Create{pascalCaseShortClassName}();"); builder.AppendLine(""); builder.AppendLine(""); builder.AppendLine("}"); builder.AppendLine(); builder.AppendLine($"private {className} Create{pascalCaseShortClassName}()"); builder.AppendLine("{"); builder.Append($"return new {className}"); if (constructorTypes.Count > 0) { builder.AppendLine("("); for (int i = 0; i < constructorTypes.Count; i++) { string mockReferenceStatement; InjectableType constructorType = constructorTypes[i]; if (constructorType == null) { mockReferenceStatement = "TODO"; } else if (mockFramework == MockFramework.SimpleStubs) { mockReferenceStatement = $"this.stub{constructorType.TypeBaseName}"; } else { mockReferenceStatement = $"this.mock{constructorType.TypeBaseName}.Object"; } builder.Append($" {mockReferenceStatement}"); if (i < constructorTypes.Count - 1) { builder.AppendLine(","); } } builder.Append(")"); } else if (properties.Count == 0) { builder.Append("()"); } if (properties.Count > 0) { builder.AppendLine(); builder.AppendLine("{"); foreach (InjectableProperty property in properties) { string mockReferenceStatement; if (mockFramework == MockFramework.SimpleStubs) { mockReferenceStatement = $"this.stub{property.TypeBaseName}"; } else { mockReferenceStatement = $"this.mock{property.TypeBaseName}.Object"; } builder.AppendLine($"{property.Name} = {mockReferenceStatement},"); } builder.Append(@"}"); } builder.AppendLine(";"); builder.AppendLine("}"); builder.AppendLine("}"); builder.AppendLine("}"); SyntaxTree tree = CSharpSyntaxTree.ParseText(builder.ToString()); SyntaxNode formattedNode = Formatter.Format(tree.GetRoot(), CreateUnitTestBoilerplateCommandPackage.VisualStudioWorkspace); return(formattedNode.ToString()); //return builder.ToString(); }
private async Task <string> GenerateUnitTestContentsFromFileAsync(string inputFilePath) { Microsoft.CodeAnalysis.Solution solution = CreateUnitTestBoilerplateCommandPackage.VisualStudioWorkspace.CurrentSolution; DocumentId documentId = solution.GetDocumentIdsWithFilePath(inputFilePath).FirstOrDefault(); if (documentId == null) { this.HandleError("Could not find document in solution with file path " + inputFilePath); } var document = solution.GetDocument(documentId); SyntaxNode root = await document.GetSyntaxRootAsync(); SemanticModel semanticModel = await document.GetSemanticModelAsync(); SyntaxNode firstClassDeclaration = root.DescendantNodes().FirstOrDefault(node => node.Kind() == SyntaxKind.ClassDeclaration); if (firstClassDeclaration == null) { this.HandleError("Could not find class declaration."); } if (firstClassDeclaration.ChildTokens().Any(node => node.Kind() == SyntaxKind.AbstractKeyword)) { this.HandleError("Cannot unit test an abstract class."); } SyntaxToken classIdentifierToken = firstClassDeclaration.ChildTokens().FirstOrDefault(n => n.Kind() == SyntaxKind.IdentifierToken); if (classIdentifierToken == null) { this.HandleError("Could not find class identifier."); } NamespaceDeclarationSyntax namespaceDeclarationSyntax = null; if (!Utilities.TryGetParentSyntax(firstClassDeclaration, out namespaceDeclarationSyntax)) { this.HandleError("Could not find class namespace."); } MockFramework mockFramework = Utilities.FindMockFramework(this.SelectedProject.Project); TestFramework testFramework = Utilities.FindTestFramework(this.SelectedProject.Project); // Find property injection types var injectableProperties = new List <InjectableProperty>(); string classFullName = namespaceDeclarationSyntax.Name + "." + classIdentifierToken; INamedTypeSymbol classType = semanticModel.Compilation.GetTypeByMetadataName(classFullName); foreach (ISymbol member in classType.GetBaseTypesAndThis().SelectMany(n => n.GetMembers())) { if (member.Kind == SymbolKind.Property) { IPropertySymbol property = (IPropertySymbol)member; foreach (AttributeData attribute in property.GetAttributes()) { if (PropertyInjectionAttributeNames.Contains(attribute.AttributeClass.ToString())) { var injectableProperty = InjectableProperty.TryCreateInjectableProperty(property.Name, property.Type.ToString(), mockFramework); if (injectableProperty != null) { injectableProperties.Add(injectableProperty); } } } } } this.className = classIdentifierToken.ToString(); // Find constructor injection types var constructorInjectionTypes = new List <InjectableType>(); SyntaxNode constructorDeclaration = firstClassDeclaration.ChildNodes().FirstOrDefault(n => n.Kind() == SyntaxKind.ConstructorDeclaration); if (constructorDeclaration != null) { SyntaxNode parameterListNode = constructorDeclaration.ChildNodes().First(n => n.Kind() == SyntaxKind.ParameterList); var parameterNodes = parameterListNode.ChildNodes().Where(n => n.Kind() == SyntaxKind.Parameter); foreach (SyntaxNode node in parameterNodes) { constructorInjectionTypes.Add(InjectableType.TryCreateInjectableTypeFromParameterNode(node, semanticModel, mockFramework)); } } string unitTestNamespace; string defaultNamespace = this.SelectedProject.Project.Properties.Item("DefaultNamespace").Value as string; if (string.IsNullOrEmpty(this.relativePath)) { unitTestNamespace = defaultNamespace; } else { List <string> defaultNamespaceParts = defaultNamespace.Split('.').ToList(); List <string> unitTestNamespaceParts = new List <string>(defaultNamespaceParts); unitTestNamespaceParts.AddRange(this.relativePath.Split('\\')); unitTestNamespace = string.Join(".", unitTestNamespaceParts); } List <InjectableType> injectedTypes = new List <InjectableType>(injectableProperties); injectedTypes.AddRange(constructorInjectionTypes.Where(t => t != null)); GenerateMockNames(injectedTypes); // Compile information needed to generate the test var context = new TestGenerationContext( mockFramework, testFramework, unitTestNamespace, this.className, namespaceDeclarationSyntax.Name.ToString(), injectableProperties, constructorInjectionTypes, injectedTypes); return(this.GenerateUnitTestContents(context)); }