Roslyn CTP - Random Code Modification - c#

I have been experimenting with the Roslyn API in a genetic programming type of scenario. It appears like a great way to do that type of programming, but the actual implementation of simple scenarios doesn't seem very straightforward, which means I probably don't have a good understanding of how to use this API properly. Here is a simple program I am trying to modify in my experiments:
string treeText = #"using System;
using System.Collections.Generic;
namespace TestProgram
{
class Program
{
static void Main(string[] args)
{
var myVar = 3;
string myString = ""Hello World"";
List<string> stringList = new List<string>();
Console.WriteLine(myString + myVar);
Console.ReadLine();
}
}
}";
SyntaxTree tree = SyntaxTree.ParseText(treeText);
var compilation = Compilation.Create("test.exe",
syntaxTrees: new[] { tree },
references: new[]
{
new MetadataFileReference(typeof(object).Assembly.Location),
new MetadataFileReference(typeof(Enumerable).Assembly.Location),
});
SemanticModel model = compilation.GetSemanticModel(tree);
Just as a simple example let's say I somehow "randomly" decided I want to insert a new method invocation using the myString instance. What would be an efficient way to figure out what methods I could invoke off of that instance? What would then be the best way to create the necessary MethodInvocationSyntax (once I chose a specific method to use) from the symbol information? I found a method called ResolveOverloads on the SemanticModel class which appears where I need to end up, but I am having some difficulty figuring out an efficient path to the parameters this method requires. Is that even the right path to go down?

First, get the VariableDeclaratorSyntax for your variable, for example:
var variable = tree.GetRoot().DescendantNodes()
.OfType<VariableDeclaratorSyntax>()
.Single(v => v.Identifier.ValueText == "myString");
Next, get the LocalSymbol for this variable from the SemanticModel:
var variableSymbol = (LocalSymbol)model.GetDeclaredSymbol(variable);
Then you can get a list of methods you can invoke on this variable based on its type. You can either simply get all members of the type that are instance methods:
var methods =
variableSymbol.Type.GetMembers()
.OfType<MethodSymbol>()
.Where(m => !m.IsStatic && m.MethodKind == MethodKind.Ordinary);
Or, if you wanted to include extension methods, you could use LookupSymbols():
var methods = model.LookupSymbols(
variable.GetLocation().SourceSpan.Start, variableSymbol.Type,
options: LookupOptions.IncludeExtensionMethods)
.Where(m => !m.IsStatic);
You can then choose one of the available methods based on your logic and create InvocationExpressionSyntax (the following code assumes it's a parameterless method):
var invocationExpression =
Syntax.InvocationExpression(
Syntax.MemberAccessExpression(
SyntaxKind.MemberAccessExpression,
Syntax.IdentifierName(variableSymbol.Name),
(SimpleNameSyntax)Syntax.ParseName(selectedMethod.Name)));
You would then need to figure out where in your method to add the expression and what to do with its result (if anything).

Related

Generate code for classes with an attribute

I have the following setup :
public class CustomAttribute : Attribute
{
[...]
public CustomAttribute(Type type)
{
[...]
}
}
[Custom(typeof(Class2))]
public class Class1
{
public void M1(Class2) {}
public void M2(Class2) {}
}
public partial class Class2
{
[...]
}
What I am trying to achieve using the new Code Generation mechanism added in .NET 5 is at compile-time, find every class in the project referencing my generator being annotated by the Custom attribute, and then, create a partial class for the type in its constructor containing methods having the same name and parameters (It won't be the same parameters, it's just to simplify a bit).
Before, I was planning to use TTs to generate the partial file but creating one per type was announcing itself to be both tedious and hard to maintain.
Thing is...
I'm a little lost.
What I did manage to do:
Create a generator, making sure it is called at generation and the code it generates is usable (~ a hello world version)
Find my attribute symbol in the compilation context (not sure I'll need it, but I found it)
Found a way to identify the classes being annotated by my attribute by relying on the syntax trees present in the compilation context.
Now, though I don't know how to proceed further, the syntax tree has at the same level the identifier nodes for my attribute and the class being used as a parameter, meaning if I ever use another attribute, I fear they will all get at the same level (might use the order getting the position of the identifier for my attribute and then getting the next one).
But then even if we omit that... How can I list all methods and their parameters for a given class that I have the name of? Reflection is obviously out of the picture since the assembly is not loaded.
I only found Rosly examples, based on using the solution or Analyzers who don't really have the same type of objects available, and thus the proposed solutions are not applicable. And I'm not sure starting another Roslyn analysis on single files is really the way it is supposed to be done.
Please keep in mind that this is my first foray with the Semantic/Syntaxic API.
Preparatory work: Introduction to C# source generators
This will guide you towards settings up a code generator project. As far as I understood, tooling is on the way to automate this part.
TL;DR there will be the full ExecuteMethod at the end of this answer
Filtering out the syntaxic trees containing no classes decorated with an attribute
This is our first step, we only want to work with the classes that are decorated by an attribute, we'll then make sure it's the one that interests us. This also has the secondary benefit of filtering out any source files that do not contain classes (think AssemblyInfo.cs)
In the Execute method of our new Generator, we will be able to use Linq to filter out the trees:
var treesWithlassWithAttributes = context.Compilation.SyntaxTrees.Where(st => st.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>()
.Any(p => p.DescendantNodes().OfType<AttributeSyntax>().Any()));
We will then be able to loop on our syntaxic trees (from what I could see, one syntaxic tree corresponds roughly to one file)
Filter-out classes not being annotated with an attribute
The next step is to make sure that in our current syntaxic tree, we only work on classes being decorated by an attribute (for the cases where several classes are declared in one file).
var declaredClass = tree
.GetRoot()
.DescendantNodes()
.OfType<ClassDeclarationSyntax>()
.Where(cd => cd.DescendantNodes().OfType<AttributeSyntax>().Any())
This is all pretty similar to the previous step, tree being one of the items we got in our treesWithClassWithAttributes collection.
Once again, we'll loop on that collection.
Filter-out classes that are not annotated with our specific attribute
Now, that we are working on single classes, we can dive in and check if any of the attributes are the one we are looking for. This will also be the first time we will need the semantic API, since the attribute identifier is not it's class name (PropertyAttribute, will be used as [Property] for example), and the semantic API, allows us to find the original class name without us having to guess.
We will first need to initialize our semantic model (this should placed in our top level loop):
var semanticModel = context.Compilation.GetSemanticModel(tree);
Once initialized, we get to our searching :
var nodes = declaredClass
.DescendantNodes()
.OfType<AttributeSyntax>()
.FirstOrDefault(a => a.DescendantTokens().Any(dt => dt.IsKind(SyntaxKind.IdentifierToken) && semanticModel.GetTypeInfo(dt.Parent).Type.Name == attributeSymbol.Name))
?.DescendantTokens()
?.Where(dt => dt.IsKind(SyntaxKind.IdentifierToken))
?.ToList();
Note: attributeSymbol is a variable holding the Type of the attribute I am searching for
What we are doing here, is for each syntaxic node related to our class declaration, we only look at the ones describing an attribute declaration.
We then take the first one (my attribute can only be placed once on a class) that has an IdentifierToken for which the parent node Is of the type of my attribute (the semantic API does NOT return a Type hence the name Comparison).
For the next steps, I will need the IdentifiersToken, so we'll use the Elvis operator to get them if we found our attribute, we'll get a null result otherwise which will allow us to get to the next iteration of our loop.
Get the class type used as my Attribute parameter
This is where it gets really specific to my use case, but it's part of the question, so I'll cover it anyway.
What we got at the end of the last step was a list of Identifier Tokens, which mean, we will have only two for my attribute : The first one Identifying the attribute itself, and the second one identifying the class I want to get the name of.
We will be using the semantic API again, this allows me to avoid looking in all the syntax trees to find the class we identified :
var relatedClass = semanticModel.GetTypeInfo(nodes.Last().Parent);
This gives us an object similar to the ones we were manipulating until now.
This is a good point to start generating our new class file (so a new stringbuilder, with all the test needed to have a partial class in the same namespace the other one was, it will always be the same in my case, so I went and wrote it directly)
To get the name of the type in relatedClass => relatedClass.Type.Name
List all methods used in a class
So now, to list all the methods in the annotated class. Remember we are looping on classes here, coming from our syntactic tree.
To obtain a list of all the methods declared in this class we will ask to list the member of type method
IEnumerable<MethodDeclarationSyntax> classMethod = declaredClass.Members.Where(m => m.IsKind(SyntaxKind.MethodDeclaration)).OfType<MethodDeclarationSyntax>()
I will strongly recommend either casting to MethodDeclarationSyntax or assigning to a variable with the explicit type, because it is stored as a base type that does not expose all of the properties we'll need.
Once we've got our methods, we will once again loop on them.
Here are the few properties I needed for my use case :
methodDeclaration.Modifiers //public, static, etc...
methodDeclaration.Identifier // Quite obvious => the name
methodDeclaration.ParameterList //The list of the parameters, including type, name, default values
The rest was just a matter of constructing a string representing my target partial class which is now a pretty simple matter.
The final solution
Remember that's what I came up with as my first try, I will most probably submit it on the CodeReview StackExchange to see what could be improved.
And the RelatedModelaAttribute is basically the CustomAttribute class from my question.
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using SpeedifyCliWrapper.SourceGenerators.Annotations;
using System.Linq;
using System.Text;
namespace SpeedifyCliWrapper.SourceGenerators
{
[Generator]
class ModuleModelGenerator : ISourceGenerator
{
public void Execute(GeneratorExecutionContext context)
{
var attributeSymbol = context.Compilation.GetTypeByMetadataName(typeof(RelatedModelAttribute).FullName);
var classWithAttributes = context.Compilation.SyntaxTrees.Where(st => st.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>()
.Any(p => p.DescendantNodes().OfType<AttributeSyntax>().Any()));
foreach (SyntaxTree tree in classWithAttributes)
{
var semanticModel = context.Compilation.GetSemanticModel(tree);
foreach(var declaredClass in tree
.GetRoot()
.DescendantNodes()
.OfType<ClassDeclarationSyntax>()
.Where(cd => cd.DescendantNodes().OfType<AttributeSyntax>().Any()))
{
var nodes = declaredClass
.DescendantNodes()
.OfType<AttributeSyntax>()
.FirstOrDefault(a => a.DescendantTokens().Any(dt => dt.IsKind(SyntaxKind.IdentifierToken) && semanticModel.GetTypeInfo(dt.Parent).Type.Name == attributeSymbol.Name))
?.DescendantTokens()
?.Where(dt => dt.IsKind(SyntaxKind.IdentifierToken))
?.ToList();
if(nodes == null)
{
continue;
}
var relatedClass = semanticModel.GetTypeInfo(nodes.Last().Parent);
var generatedClass = this.GenerateClass(relatedClass);
foreach(MethodDeclarationSyntax classMethod in declaredClass.Members.Where(m => m.IsKind(SyntaxKind.MethodDeclaration)).OfType<MethodDeclarationSyntax>())
{
this.GenerateMethod(declaredClass.Identifier, relatedClass, classMethod, ref generatedClass);
}
this.CloseClass(generatedClass);
context.AddSource($"{declaredClass.Identifier}_{relatedClass.Type.Name}", SourceText.From(generatedClass.ToString(), Encoding.UTF8));
}
}
}
public void Initialize(GeneratorInitializationContext context)
{
// Nothing to do here
}
private void GenerateMethod(SyntaxToken moduleName, TypeInfo relatedClass, MethodDeclarationSyntax methodDeclaration, ref StringBuilder builder)
{
var signature = $"{methodDeclaration.Modifiers} {relatedClass.Type.Name} {methodDeclaration.Identifier}(";
var parameters = methodDeclaration.ParameterList.Parameters.Skip(1);
signature += string.Join(", ", parameters.Select(p => p.ToString())) + ")";
var methodCall = $"return this._wrapper.{moduleName}.{methodDeclaration.Identifier}(this, {string.Join(", ", parameters.Select(p => p.Identifier.ToString()))});";
builder.AppendLine(#"
" + signature + #"
{
" + methodCall + #"
}");
}
private StringBuilder GenerateClass(TypeInfo relatedClass)
{
var sb = new StringBuilder();
sb.Append(#"
using System;
using System.Collections.Generic;
using SpeedifyCliWrapper.Common;
namespace SpeedifyCliWrapper.ReturnTypes
{
public partial class " + relatedClass.Type.Name);
sb.Append(#"
{");
return sb;
}
private void CloseClass(StringBuilder generatedClass)
{
generatedClass.Append(
#" }
}");
}
}
}
Inside the Execute method of your generator, add this:
var classesWithAttribute = context.Compilation.SyntaxTrees
.SelectMany(st => st.GetRoot()
.DescendantNodes()
.Where(n => n is ClassDeclarationSyntax)
.Select(n => n as ClassDeclarationSyntax)
.Where(r => r.AttributeLists
.SelectMany(al => al.Attributes)
.Any(a => a.Name.GetText().ToString() == "Foo")));
This basically takes all the nodes of all the trees, filters out nodes that are not class declarations, and, for each class declaration, looks if any of its attributes matches our custom attribute, "Foo" here.
Note: if your attribute is named FooAttribute, then you look for Foo, not FooAttribute.
// In SourceGenerator
public void Initialize(GeneratorInitializationContext context)
{
#if DEBUG
if (!Debugger.IsAttached)
{
//Debugger.Launch();
}
#endif
context.RegisterForSyntaxNotifications(() => new MySyntaxReceiver());
}
public void Execute(GeneratorExecutionContext context)
{
MySyntaxReceiver syntaxReceiver = (MySyntaxReceiver)context.SyntaxReceiver;
}
class MySyntaxReceiver : ISyntaxReceiver
{
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{
// Note that the attribute name, is without the ending 'Attribute' e.g TestAttribute -> Test
if (syntaxNode is ClassDeclarationSyntax cds && cds.AttributeLists.Count > 0)
{
var syntaxAttributes = cds.AttributeLists.SelectMany(e => e.Attributes)
.Where(e => e.Name.NormalizeWhitespace().ToFullString() == "Test")
if (syntaxAttributes.Any())
{
// Do what you want with cds
}
}
}
}

Detect access to data from a method in c#

I have a method and I want to find all data accessed inside this method.
for example:
public class foo
{
private int field;
public void method()
{
field = 0;
}
}
I need a way to know (from the source code or the assembly) that 'field' is accessed within 'method'.
Note: I already used Harmony Library (https://github.com/pardeike/Harmony) to find all the calls to methods inside a specific method. It would be amazing if someone knows how to use it to also find data accessed.
as pointed out in comments, Roslyn DataFlowAnalysis is probably the best tool for the job:
SyntaxTree tree = CSharpSyntaxTree.ParseText(
#"public class foo
{
private int field;
public void method()
{
field = 0;
}
}");
var compilation = CSharpCompilation.Create("test").AddSyntaxTrees(tree).AddReferences(MetadataReference.CreateFromFile(typeof(object).Assembly.Location));
var model = compilation.GetSemanticModel(tree);
var methodDeclaration = tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().First();
var dataFlow = model.AnalyzeDataFlow(methodDeclaration.Body);
foreach (var symbol in dataFlow.DataFlowsIn)
{
Console.WriteLine(symbol.Name, symbol.Kind);
}
analysis for your particular example yields reference to class foo through implicit
this, but not the field itself (which is technically correct but not very helpful). Assuming your actual code will likely have a bit more dependencies in it - you may see better results.
If you look at the list of opcodes in IL you find that you want to search for OpCodes.Ldfld and OpCodes.Ldflda. Harmony’s CodeInstruction has two fields to use: compare code to either opcode and use operand and cast it to a FieldInfo to learn about what field is read. Use OpCodes.Stfld(a) for write access to fields.

C#, Generics, Type and NHibernate

I'm learning the power of generics in C# in conjunction with NHibernate. I'd like to attempt the following in the pasted code.
In an attempt to do some post processing of N number of NHibernate objects I worked on a utility method leveraging generics to make it applicable to all NHibernate mapping classes we use now, or in the future. It works but I need to hard code each call for each mapping class. This is a pain and will need continuing updating as our schema and mappings change over time.
I do have an ever up-to-date list of all mapping classes by string name through the NHibernate mappings I generate on the fly. If there was a way to use this list of string names to call my generics based method, I'd be super happy.
Can anyone tell me if this is possible? Do I need to find another route?
Thanks so much in advance!!!
public static void ProcessSomeItems()
{
// *************************************************************
// As of now I have to list all classes as such to be processed
// It works but I have to update manually when new mapping classes are created
// *************************************************************
NHibDoSomethingUtil<AspnetMembership>();
NHibDoSomethingUtil<AspnetProfile>();
NHibDoSomethingUtil<AspnetRole>();
NHibDoSomethingUtil<AspnetUser>();
// and so forth...
// I have a up-to-date list of all mappings from "HbmMapping" and can get a list of all in the
// list form as below
List<string> mappingNames = new List<string>();
foreach (string mappingName in mappingNames)
{
Type theType = Type.GetType(mappingName);
// I know I'm getting Types and Generics classes and so forth all jumbled but
// how in the heck would I do something like the below?
NHibDoSomethingUtil<theType>(); // Obviously doesn't compile ;-)
}
}
// Generic method
public static void NHibDoSomethingUtil<T>() where T : class
{
using (ISession session = sourceDBSessionFactory.OpenSession())
{
foreach (dynamic item in new List<T>(session.QueryOver<T>().List()))
{
// Process item;
}
}
}
ecsousa gave great input and I was able to accomplish what I needed with something like the following.
foreach (HbmClass mappingClass in mapping.Items)
{
Console.WriteLine(" -- Discovered Mapping: " + mappingClass.Name);
Type mappingClassType = Type.GetType(mappingClass.Name);
var genericMethod = typeof(Migration).GetMethod("NHibDoSomethingUtil");
var method = genericMethod.MakeGenericMethod(mappingClassType);
method.Invoke(null, null);
}
You will need to use Reflection in order to accomplish this. Instead of directly calling NHibDoSomethingUtil, try this:
var genericMethod = typeof(TheClassName).GetMethod("NHibDoSomethingUtil");
var method = genericMethod.MakeGenericMethod(theType);
method.Invoke(null, null);
Note that you have to replace TheClassName by the class containing both methods.
Keep in mind the this kind of code is slow, and you should use it very carefully.

Dynamically find used properties prior to them being used

I am looking for optimization of a pattern I am using for a dynamic forms application.
I have a repository class with a method:
public Entity Find(string objectId, List<string> includedProperties);
This returns an Entity object, with only the fields specified in the "includedProperties", as building the entire object for all purposes is unnecessary overhead in this case (some entities have hundreds of properties).
Example domain code using this repository often looks something like this:
var includedProperties = new List<string> {
"FirstChildName" ,
"FirstChildDob",
"SecondChildName",
"SecondChildDob"
}
I then fetch an object:
var person = repository.Find("123",includedProperties);
I then use the Properties with a GetProperty(string propertyName) method:
var firstChildDob = person.GetProperty("FirstChildDob").AsDateTime();
...etc
This all works fine, and fits well with the dynamic design of the application. However, I find it irritating that I always need to declare a list of "used" properties separately, prior to fetching the object.
So, my question is, through reflection or some other cleverness, can I simplify the building of the "Included Properties" by looking at which parameters get passed later in the code with the "GetProperty" method?
Using the above example, I'd like to build the list using a helper like this (or similar):
var includedProperties = HelperObject.GetFieldsUsedInCurrentCodeFile();
This would somehow pickup what string constants were passed to the "GetProperty()" method, saving the need for explicit declaration. Any suggestions welcome!
I actually had a similar problem awhile back; the best I could come up with at the time was to define an enum that contained the names of the properties I wanted to use in the method.
Using this approach, you could build the list of included properties by cycling through the enum.
There are a couple of benefits to this approach vs. strings:
Any property spelling issues or property name changes are made in a single location.
If you are using a tool such as Resharper, you can determine when you have unused "properties" in the enum.
For example:
private enum PersonMethodProperties
{
FirstChildName,
FirstChildDob,
SecondChildName,
SecondChildDob
}
private void PersonMethod()
{
var includedProperties = GetIncludePropertiesFromEnum(typeof(PersonMethodProperties));
var person = repository.Find("123", includedProperties);
var firstChildDob = person.GetProperty(PersonMethodProperties.FirstChildDob.ToString()).AsDateTime();
}
private List<string> GetIncludePropertiesFromEnum(Type propertiesEnumType)
{
var includedProperties = new List<string>();
foreach (var name in Enum.GetNames(propertiesEnumType))
{
includedProperties.Add(name);
}
return includedProperties;
}
Code analysis tools like Nitriq or NDepend unfortunately won't help you because in current version they do not capture method's arguments names and values.
But you can use Roslyn to create tool that will analyze your solution and generate a class containing list with used properties as a pre-build event. Code for solution analysis that finds all calls to className.methodName and returns its constant arguments (text in your case):
static IEnumerable<string> GetMethodCallParametersValues(string solutionName,
string className,
string methodName)
{
var workspace = Workspace.LoadSolution(solutionName);
var solution = workspace.CurrentSolution;
var createCommandList = new List<ISymbol>();
var #class = solution.Projects.Select(s => s.GetCompilation()
.GetTypeByMetadataName(className))
.FirstOrDefault();
var method = #class.GetMembers(methodName)
.AsList()
.Where(s => s.Kind == CommonSymbolKind.Method)
.FirstOrDefault();
var locations = method.FindReferences(solution)
.SelectMany(r => r.Locations);
List<string> result = new List<string>();
foreach (var location in locations)
{
var model = location.Document.GetSemanticModel();
var token = location.Location
.SourceTree
.GetRoot()
.FindToken(location.Location.SourceSpan.Start);
var invocation = token.Parent.FirstAncestorOrSelf<InvocationExpressionSyntax>();
var arguments = invocation.ArgumentList.Arguments;
result.AddRange(arguments.Select(a => model.GetConstantValue(a.Expression).Value.ToString()));
}
return result.Distinct();
}
and code usage:
var includedProperties = GetMethodCallParametersValues(#"c:\path\to\your.sln",
"SomeNamespace.SomeClass",
"GetProperty");
Note: Because of Roslyn's small bug in parsing Solution file, you probably will have to comment below lines in .sln file by adding # so they will look:
# VisualStudioVersion = 12.0.21005.1
# MinimumVisualStudioVersion = 10.0.40219.1

Using Moq to verify calls are made in the correct order

I need to test the following method:
CreateOutput(IWriter writer)
{
writer.Write(type);
writer.Write(id);
writer.Write(sender);
// many more Write()s...
}
I've created a Moq'd IWriter and I want to ensure that the Write() methods are called in the right order.
I have the following test code:
var mockWriter = new Mock<IWriter>(MockBehavior.Strict);
var sequence = new MockSequence();
mockWriter.InSequence(sequence).Setup(x => x.Write(expectedType));
mockWriter.InSequence(sequence).Setup(x => x.Write(expectedId));
mockWriter.InSequence(sequence).Setup(x => x.Write(expectedSender));
However, the second call to Write() in CreateOutput() (to write the id value) throws a MockException with the message "IWriter.Write() invocation failed with mock behavior Strict. All invocations on the mock must have a corresponding setup.".
I'm also finding it hard to find any definitive, up-to-date documentation/examples of Moq sequences.
Am I doing something wrong, or can I not set up a sequence using the same method?
If not, is there an alternative I can use (preferably using Moq/NUnit)?
There is bug when using MockSequence on same mock. It definitely will be fixed in later releases of Moq library (you can also fix it manually by changing Moq.MethodCall.Matches implementation).
If you want to use Moq only, then you can verify method call order via callbacks:
int callOrder = 0;
writerMock.Setup(x => x.Write(expectedType)).Callback(() => Assert.That(callOrder++, Is.EqualTo(0)));
writerMock.Setup(x => x.Write(expectedId)).Callback(() => Assert.That(callOrder++, Is.EqualTo(1)));
writerMock.Setup(x => x.Write(expectedSender)).Callback(() => Assert.That(callOrder++, Is.EqualTo(2)));
I've managed to get the behaviour I want, but it requires downloading a 3rd-party library from http://dpwhelan.com/blog/software-development/moq-sequences/
The sequence can then be tested using the following:
var mockWriter = new Mock<IWriter>(MockBehavior.Strict);
using (Sequence.Create())
{
mockWriter.Setup(x => x.Write(expectedType)).InSequence();
mockWriter.Setup(x => x.Write(expectedId)).InSequence();
mockWriter.Setup(x => x.Write(expectedSender)).InSequence();
}
I've added this as an answer partly to help document this solution, but I'm still interested in whether something similar could be achieved using Moq 4.0 alone.
I'm not sure if Moq is still in development, but fixing the problem with the MockSequence, or including the moq-sequences extension in Moq would be good to see.
I wrote an extension method that will assert based on order of invocation.
public static class MockExtensions
{
public static void ExpectsInOrder<T>(this Mock<T> mock, params Expression<Action<T>>[] expressions) where T : class
{
// All closures have the same instance of sharedCallCount
var sharedCallCount = 0;
for (var i = 0; i < expressions.Length; i++)
{
// Each closure has it's own instance of expectedCallCount
var expectedCallCount = i;
mock.Setup(expressions[i]).Callback(
() =>
{
Assert.AreEqual(expectedCallCount, sharedCallCount);
sharedCallCount++;
});
}
}
}
It works by taking advantage of the way that closures work with respect to scoped variables. Since there is only one declaration for sharedCallCount, all of the closures will have a reference to the same variable. With expectedCallCount, a new instance is instantiated each iteration of the loop (as opposed to simply using i in the closure). This way, each closure has a copy of i scoped only to itself to compare with the sharedCallCount when the expressions are invoked.
Here's a small unit test for the extension. Note that this method is called in your setup section, not your assertion section.
[TestFixture]
public class MockExtensionsTest
{
[TestCase]
{
// Setup
var mock = new Mock<IAmAnInterface>();
mock.ExpectsInOrder(
x => x.MyMethod("1"),
x => x.MyMethod("2"));
// Fake the object being called in order
mock.Object.MyMethod("1");
mock.Object.MyMethod("2");
}
[TestCase]
{
// Setup
var mock = new Mock<IAmAnInterface>();
mock.ExpectsInOrder(
x => x.MyMethod("1"),
x => x.MyMethod("2"));
// Fake the object being called out of order
Assert.Throws<AssertionException>(() => mock.Object.MyMethod("2"));
}
}
public interface IAmAnInterface
{
void MyMethod(string param);
}
The simplest solution would be using a Queue:
var expectedParameters = new Queue<string>(new[]{expectedType,expectedId,expectedSender});
mockWriter.Setup(x => x.Write(expectedType))
.Callback((string s) => Assert.AreEqual(expectedParameters.Dequeue(), s));
Recently, I put together two features for Moq: VerifyInSequence() and VerifyNotInSequence(). They work even with Loose Mocks. However, these are only available in a moq repository fork:
https://github.com/grzesiek-galezowski/moq4
and await more comments and testing before deciding on whether they can be included in official moq releaase. However, nothing prevents you from downloading the source as ZIP, building it into a dll and giving it a try. Using these features, the sequence verification you need could be written as such:
var mockWriter = new Mock<IWriter>() { CallSequence = new LooseSequence() };
//perform the necessary calls
mockWriter.VerifyInSequence(x => x.Write(expectedType));
mockWriter.VerifyInSequence(x => x.Write(expectedId));
mockWriter.VerifyInSequence(x => x.Write(expectedSender));
(note that you can use two other sequences, depending on your needs. Loose sequence will allow any calls between the ones you want to verify. StrictSequence will not allow this and StrictAnytimeSequence is like StrictSequence (no method calls between verified calls), but allows the sequence to be preceeded by any number of arbitrary calls.
If you decide to give this experimental feature a try, please comment with your thoughts on:
https://github.com/Moq/moq4/issues/21
Thanks!
I've just had a similar scenario, and inspired by the accepted answer, I've used the following approach:
//arrange
var someServiceToTest = new SomeService();
var expectedCallOrder = new List<string>
{
"WriteA",
"WriteB",
"WriteC"
};
var actualCallOrder = new List<string>();
var mockWriter = new Mock<IWriter>();
mockWriter.Setup(x => x.Write("A")).Callback(() => { actualCallOrder.Add("WriteA"); });
mockWriter.Setup(x => x.Write("B")).Callback(() => { actualCallOrder.Add("WriteB"); });
mockWriter.Setup(x => x.Write("C")).Callback(() => { actualCallOrder.Add("WriteC"); });
//act
someServiceToTest.CreateOutput(_mockWriter.Object);
//assert
Assert.AreEqual(expectedCallOrder, actualCallOrder);
Moq has a little-known feature called Capture.In, which can capture arguments passed to a method. With it, you can verify call order like this:
var calls = new List<string>();
var mockWriter = new Mock<IWriter>();
mockWriter.Setup(x => x.Write(Capture.In(calls)));
CollectionAssert.AreEqual(calls, expectedCalls);
If you have overloads with different types, you can run the same setup for overloads too.
My scenario was methods without parameters:
public interface IWriter
{
void WriteA ();
void WriteB ();
void WriteC ();
}
So I used Invocations property on the Mock to compare what was called:
var writer = new Mock<IWriter> ();
new SUT (writer.Object).Run ();
Assert.Equal (
writer.Invocations.Select (invocation => invocation.Method.Name),
new[]
{
nameof (IWriter.WriteB),
nameof (IWriter.WriteA),
nameof (IWriter.WriteC),
});
You could also append the invocation.Arguments to check method calls with parameters.
Also the failure message is more clear than just expected 1 but was 5:
expected
["WriteB", "WriteA", "WriteC"]
but was
["WriteA", "WriteB"]
I suspect that expectedId is not what you expect.
However i'd probably just write my own implementation of IWriter to verify in this case ... probably a lot easier (and easier to change later).
Sorry for no Moq advice directly. I love it, but haven't done this in it.
do you maybe need to add .Verify() at the end of each setup? (That really is a guess though i'm afraid).
I am late to this party but I wanted to share a solution that worked for me since it seems as though all of the referenced solutions did not work with verifying the same method call (with the same arguments) multiple times in order. In addition the referenced bug, Moq Issue #478 was closed without a solution.
The solution presented utilizes the MockObject.Invocations list to determine order and sameness.
public static void VerifyInvocations<T>(this Mock<T> mock, params Expression<Action<T>>[] expressions) where T : class
{
Assert.AreEqual(mock.Invocations.Count, expressions.Length,
$"Number of invocations did not match expected expressions! Actual invocations: {Environment.NewLine}" +
$"{string.Join(Environment.NewLine, mock.Invocations.Select(i => i.Method.Name))}");
for (int c = 0; c < mock.Invocations.Count; c++)
{
IInvocation expected = mock.Invocations[c];
MethodCallExpression actual = expressions[c].Body as MethodCallExpression;
// Verify that the same methods were invoked
Assert.AreEqual(expected.Method, actual.Method, $"Did not invoke the expected method at call {c + 1}!");
// Verify that the method was invoked with the correct arguments
CollectionAssert.AreEqual(expected.Arguments.ToList(),
actual.Arguments
.Select(arg =>
{
// Expressions treat the Argument property as an Expression, do this to invoke the getter and get the actual value.
UnaryExpression objectMember = Expression.Convert(arg, typeof(object));
Expression<Func<object>> getterLambda = Expression.Lambda<Func<object>>(objectMember);
Func<object> objectValueGetter = getterLambda.Compile();
return objectValueGetter();
})
.ToList(),
$"Did not invoke step {c + 1} method '{expected.Method.Name}' with the correct arguments! ");
}
}

Categories