Roslyn dynamic class generation issue - roslyn

So I am trying to create a dynamic type (at runtime) using Roslyn. The entire back story to this requirement is too long to go into. I do however need to create a new type which has x many properties, where I am trying to feed in the property names and initial values from a Dictionary
Here is the relevant code
private void CreateAssembly(Dictionary<string, string> propertiesToEmit)
{
if (ourAssembly == null)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("using System;");
sb.AppendLine("public class MyClass");
sb.AppendLine("{");
sb.AppendLine(" public static void Main()");
sb.AppendLine(" {");
sb.AppendLine(" }");
foreach (var kvp in propertiesToEmit)
{
sb.AppendLine($" public {kvp.Value} {kvp.Key}" + " { get; set; }");
}
sb.AppendLine(" public MyClass CreateFromDynamic(Dictionary<string, object> sourceItem)");
sb.AppendLine(" {");
sb.AppendLine(" MyClass newOne = new MyClass();");
foreach (var kvp in propertiesToEmit)
{
sb.AppendLine($#" newOne.{kvp.Key} = sourceItem[""{kvp.Key}""];");
}
sb.AppendLine(" return newOne;");
sb.AppendLine(" }");
sb.AppendLine("}");
var tree = CSharpSyntaxTree.ParseText(sb.ToString());
var mscorlib = MetadataReference.CreateFromFile(typeof(object).Assembly.Location);
var dictsLib = MetadataReference.CreateFromFile(typeof(Dictionary<,>).Assembly.Location);
var compilation = CSharpCompilation.Create("MyCompilation",
syntaxTrees: new[] { tree }, references: new[] { mscorlib, dictsLib });
//Emit to stream
var ms = new MemoryStream();
var emitResult = compilation.Emit(ms);
//Load into currently running assembly. Normally we'd probably
//want to do this in an AppDomain
ourAssembly = Assembly.Load(ms.ToArray());
}
}
I get this weird error with Roslyn where it can't seem to find a reference to Dictionary<,> even though this is inside mscorlib which is referenced.
It can clearly be seen that Dictionary<,> does live in a dll (namely mscorlib) that is referenced.
Any ideas?

Ok I found the answer, I forgot to add this using statement in code I was creating out using Roslyn
sb.AppendLine("using System.Collections.Generic;");

Related

How to unit test a repository and mock db with moq

I am onboarding alone on an existing project that do not have any unit test. My first goal before any refactoring is to cover 100% of the code. I would like to avoid any regression.
I have read how do I mock sqlconnection or should I refactor the code? but my case as you can see below is quite different cause I need to do more than stub simply the sqlConnection. Basically, I need to mock the db. I would like to know the best approach to achieve it.
(By the way, I do not want to use any ORM such as Entity).
Below the code of the repository :
public class HotelRepository : IHotelRepository
{
private readonly IDbConnection _dbConnection;
private readonly ILogService _loggerService;
public HotelRepository(IDbConnection dbConnection, ILogService loggerService)
{
_dbConnection = dbConnection;
_loggerService = loggerService;
}
public HotelDo GetByRid(string rid)
{
return Find(rid).FirstOrDefault();
}
public List<HotelDo> Find(string text)
{
try
{
_dbConnection.Open();
var items = new List<HotelDo>();
using (var command = _dbConnection.CreateCommand())
{
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "dbo.HotelSearchByRidOrName";
command.Parameters.Add(new SqlParameter("#Text", text));
using (var reader = command.ExecuteReader(CommandBehavior.CloseConnection))
{
while (reader.Read())
{
items.Add(new HotelDo()
{
Name = SqlExtension.ReaderToStringConverter(reader["Name"]),
Id = SqlExtension.ReaderToIntConverter(reader["Id"]),
Rid = SqlExtension.ReaderToStringConverter(reader["RIDHotel"]),
IdPms = SqlExtension.ReaderToNullableIntConverter(reader["IdPms"]),
LinkResaWeb = SqlExtension.ReaderToStringConverter(reader["LinkResaWeb"]),
LinkPms = SqlExtension.ReaderToStringConverter(reader["LinkPms"]),
IdBrand = SqlExtension.ReaderToNullableIntConverter(reader["IdBrand"]) ?? 0,
IsOnline = SqlExtension.ReaderToBoolConverter(reader["IsOnline"]) ?? false,
CodeCountry = SqlExtension.ReaderToStringConverter(reader["CodeCountry"])
});
}
}
}
return items;
}
catch (Exception e)
{
var errorMessage = $"HotelRepository Find, text {text} ";
_loggerService.Trace(LogSeverity.Error, errorMessage, e);
throw new DalException() { Source = errorMessage, };
}
finally
{
_dbConnection.Close();
}
}
public List<HotelDo> GetAll()
{
try
{
_dbConnection.Open();
var items = new List<HotelDo>();
using (var command = _dbConnection.CreateCommand())
{
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "dbo.HotelGetAll";
using (var reader = command.ExecuteReader(CommandBehavior.CloseConnection))
{
while (reader.Read())
{
bool.TryParse(reader["IsOnline"].ToString(), out var isOnline);
items.Add(new HotelDo()
{
Id = SqlExtension.ReaderToIntConverter(reader["Id"]),
Rid = SqlExtension.ReaderToStringConverter(reader["RIDHotel"]),
Name = SqlExtension.ReaderToStringConverter(reader["Name"]),
CodeCountry = SqlExtension.ReaderToStringConverter(reader["CodeCountry"]),
LinkPms = SqlExtension.ReaderToStringConverter(reader["LinkPms"]),
IdPms = SqlExtension.ReaderToNullableIntConverter(reader["IdPms"]),
IdBrand = SqlExtension.ReaderToNullableIntConverter(reader["IdBrand"]) ?? 0,
LinkResaWeb = SqlExtension.ReaderToStringConverter(reader["LinkResaWeb"]),
IsOnline = isOnline
});
}
}
}
return items;
}
catch (Exception e)
{
var errorMessage = $"HotelRepository GetAllHotels";
_loggerService.Trace(LogSeverity.Error, errorMessage, e);
throw new DalException() { Source = errorMessage, };
}
finally
{
_dbConnection.Close();
}
}
}
Thank you for your help
So based on what you've got I've set up a test frame for you to follow. I've removed less important components for breviety.
Before you you jump in I just want to give my 2 cents, if you don't know how to do this sort of thing you seem to be more or less in a junior position or less experiance with C# and also found your self in a more or less mature company that doesn't care about the development deparment, since an uncovered project just get's thrown your way says you don't have alot of resources to go about to imrpove the code base.
Test only the things that have business value (can you put a price on the piece of logic if it brakes)
Delivering stuff faster will make you look better as a programmer (noone in the business gives a damn about test covarage)
Study hard, get your experiance, good reputation and don't be afraid to get the hell out of there as soon as you start getting bored.
Main
void Main()
{
var idIndex = 0;
var ids = new string[] { "1", "2" };
var mockDataReader = new Mock<IDataReader>();
mockDataReader.SetupSequence(x => x.Read()).Returns(true).Returns(true).Returns(false);
mockDataReader.SetupGet(x => x["Id"]).Returns(() => ids[idIndex]).Callback(() => idIndex++);
var mockParameters = new Mock<IDataParameterCollection>();
var mockCommand = new Mock<IDbCommand>();
mockCommand.SetupGet(x => x.Parameters).Returns(mockParameters.Object);
mockCommand.Setup(x => x.ExecuteReader(CommandBehavior.CloseConnection)).Returns(mockDataReader.Object);
var mockConnection = new Mock<IDbConnection>();
mockConnection.Setup(x => x.CreateCommand()).Returns(mockCommand.Object);
var repo = new HotelRepository(mockConnection.Object);
var result = repo.Find("search");
Assert.Equal("1", result[0].Id);
Assert.Equal("2", result[1].Id);
}
Repository
public class HotelRepository
{
private readonly IDbConnection _dbConnection;
public HotelRepository(IDbConnection dbConnection)
{
_dbConnection = dbConnection;
}
public List<Pony> Find(string text)
{
_dbConnection.Open();
var items = new List<Pony>();
using (var command = _dbConnection.CreateCommand())
{
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "dbo.HotelSearchByRidOrName";
command.Parameters.Add(new SqlParameter("#Text", text));
using (var reader = command.ExecuteReader(CommandBehavior.CloseConnection))
{
while (reader.Read())
{
items.Add(new Pony
{
Id = reader["Id"].ToString()
});
}
}
}
return items;
}
}
Just a dumb o'l pony
public class Pony {
public string Id { get; set; }
}

Iron Python throws exception on testing environment

I'm having a code which runs Iron Python scripts on VS 2010. Every time a test completes I get an exception of type ObjectDisposedException, with the description: Cannot write to a closed TextWriter. I can't see the stack trace. I'm accessing the scripts via this wrapper:
public static class PythonWrapper
{
public static dynamic GetClient(string clientName, string clientType)
{
var file = string.Format(#"{0}\Python\webcore.eas", Directory.GetCurrentDirectory());
dynamic result = null;
var ipy = GetRuntime();
var engine = ipy.GetEngine("py");
ScriptScope clientScope = engine.CreateScope();
if(File.Exists(file))
{
clientScope.SetVariable("asm", Assembly.Load(ServiceManager.Get<FileEncryptionSevice>().Decrypt(file)));
string dllWrapper = string.Format("import clr\n" +
"clr.AddReference(asm)\n" +
"from Clients.{0} import {1}\n" +
"del clr", clientName, clientType);
var src = engine.CreateScriptSourceFromString(dllWrapper);
var compiled = src.Compile();
compiled.Execute(clientScope);
result = clientScope.GetVariable(clientType);
}
else
{
var scope = ipy.UseFile(string.Format(#"{0}\Python\Clients\{1}.py", Directory.GetCurrentDirectory(),clientName));
result = scope.GetVariable(clientType);
}
return result;
}
private static ScriptRuntime GetRuntime()
{
var result = Python.CreateRuntime();
var engine = Python.GetEngine(result);
var baseFolder = string.Format(#"{0}\Python\", Directory.GetCurrentDirectory());
engine.SetSearchPaths(new[] {
string.Format("{0}", baseFolder),
string.Format(#"{0}\Lib\", Directory.GetCurrentDirectory())
});
return result;
}
}
I guess I'm attempting to access a disposed object but none of the scripting objects is IDisposable. I've also tried calling ScriptRuntime.ShutDown at the end of each test, but it only has the test stuck.
Please help me.
Kind regards,
Izhar
Turns out it was a simple bug of setting an output stream for the iron python. The following code solved the error
private static void SetOutputStream(ScriptEngine engine)
{
ScriptScope sys = engine.GetSysModule();
sys.SetVariable("stdout", new PythonStreamWrapper(LogLevel.Debug));
sys.SetVariable("stderr", new PythonStreamWrapper(LogLevel.Debug));
}
public class PythonStreamWrapper
{
private readonly ILogger _logger = LoggerService.GetLogger("Obj.Gen");
private LogLevel _logLevel;
public PythonStreamWrapper(LogLevel logLevel)
{
_logLevel = logLevel;
}
public void write(string text)
{
if (text.Trim() == "") return;
_logger.Write(_logLevel, text);
}
public int softspace
{
get;
set;
}
}

how do you mock an xml for unit testing?

I need to unit testing this GetData method.
public MessageResponse GetData(XmlElement requestElement)
{
MessageResponse MsgResponse = new MessageResponse();
if (requestElement.Attributes["employeeNo"] == null){
MsgResponse.Messages = new List<string>();
MsgResponse.Messages.Add("Attribute employeeNo is missing");
MsgResponse.Error = true;
return MsgResponse;
}
if (requestElement.Attributes["xmlEmployeeName"] == null){
MsgResponse.Messages.Add("Attribute xmlEmployeeName is missing");
MsgResponse.Error = true;
return MsgResponse;
}
return MsgResponse;
}
this method needs a XmlElement parameter. how do I mock it? in my code, I first created a xmlDocument, then load the xml file.
XmlDocument doc = new XmlDocument();
doc.Load(xmlFilePath);
requestElement = doc.DocumentElement;
for me to test it, first i need to create a xml file without employeeNo, the create antoher one without name, maybe alot more for other scenarios. it just seems like alot work. is there a better way to test it?
should I use moq or other testing framework to simplify the testing?
You can just create the element you want to test with, w/o reading a file at all:
var doc = new XmlDocument();
doc.LoadXml("<MyTestElement/>");
var myTestElement = doc.DocumentElement;
myTestElement.Attributes["employeeNo"] = "fakeId";
var response = myTestResponder.GetData(myTestElement);
//assert whatever you need to
NOTE: every time you find out that the test is too hard to write, usually this means that your class/method does too much.
I would assume, that your method verifies the input, than does something with the data provided. I would suggest that you abstract the data reading part (using some xml deserializer) to populate the data model you need for your application.
Then run validation on the result of the deserialized data. Something like:
public MessageResponse GetData(XmlElement requestElement)
{
var data = _xmlDeserializer.Deserialize(requestElement);
var validationResult = _validator.Validate(data);
if (validationResult.Errors.Count > 0)
{
//populate errors
return result;
}
_dataProcessor.DoSomethingWithData(data);
}
Take a look at FluentValidation for a nice validation library.
If you go the above route, then your tests will be much simpler.
[TestMethod]
public void GetData_Returns_Correct_Message_When_EmployeeNo_Is_Null()
{
var inputWithoutEmployeeNo = GetElement(#"<input></input>");
var actual = GetData(inputWithoutEmployeeNo);
Assert.IsTrue(actual.Error, "Error should be true when employee no. is missing");
Assert.IsNotNull(actual.Messages);
Assert.AreEqual(1, actual.Messages.Count);
Assert.AreEqual("Attribute employeeNo is missing", actual.Messages[0]);
}
private XmlElement GetElement(string xml)
{
var doc = new XmlDocument();
doc.LoadXml(xml);
return doc.DocumentElement;
}
While working on the unit test, I found out that the code throws a NullReferenceException.
The following unit test demonstrates the issue:
[TestMethod]
[ExpectedException(typeof(NullReferenceException))]
public void GetData_Throws_NullReferenceException_When_EmployeeNo_Is_Not_Null_And_XmlEmployeeName_Is_Null()
{
var inputWithoutEmployeeNo = GetElement(#"<input employeeNo='123'></input>");
GetData(inputWithoutEmployeeNo);
}
Using Moq
using System;
using System.Xml;
using Moq;
using NUnit.Framework;
namespace MockXmlTest
{
[TestFixture]
public class MyServiceTests
{
private MockSetup _mockSetup;
[SetUp]
public void Init()
{
_mockSetup = MockSetup.HappySetup();
}
[Test]
public void MyService_Should_Return_Guid()
{
//Arrange
var myService = _mockSetup.MyService.Object;
var id = 42;
var expected = Guid.Empty.ToString();
//Act
var actual = myService.GetXml(id);
//Assert
Assert.AreEqual(expected, actual.FirstChild.InnerText);
}
}
public class MyService : IMyService
{
public XmlDocument GetXml(int id)
{
var doc = new XmlDocument();
//Do real stuff
return doc;
}
}
public interface IMyService
{
XmlDocument GetXml(int id);
}
public class MockSetup
{
public Mock<IMyService> MyService { get; set; }
public MockSetup()
{
MyService = new Mock<IMyService>();
}
public static MockSetup HappySetup()
{
var mockSetup = new MockSetup();
var mockDoc = CreateMockDoc();
//Matches any id of an integer, returns a XmlDocument mock
mockSetup.MyService.Setup(m => m.GetXml(It.IsAny<int>())).Returns(mockDoc);
return mockSetup;
}
private static XmlDocument CreateMockDoc()
{
//<Main><MyGuid>00000000-0000-0000-0000-000000000000</MyGuid></Main>
XmlDocument mockDoc = new XmlDocument();
XmlElement el = (XmlElement)mockDoc.AppendChild(mockDoc.CreateElement("Main"));
el.AppendChild(mockDoc.CreateElement("MyGuid")).InnerText = It.IsAny<Guid>().ToString();
return mockDoc;
}
}
}

How to reset autofac container?

In my tests I setup an autofac container, it returns some real implementation and some mocks (DB, external systems).
The problem is that after each test I Dispose the container and create a new one:
Autofac.IContainer.Dispose() and Container = builder.Build();
The already registered instances are still there.
How can I reset the container so it would be 'like new' again?
The reason why I want to do is - I want to replace one mocked instance with another. It's being registered as Singleton.
---- EDIT
Thanks for the answers. I decided to add some more code and describe what actually I'm trying to achieve. But that is actually a topic for another (prabably already answered question - unit testing CQRS).
My app contains static IContainer property:
public static IContainer Container { get; private set; }
After each test execution I create it again by calling those two methods:
public static ContainerBuilder Compose(IEnumerable<DependencyProvider> dependencyProviders)
{
var collection = dependencyProviders as List<DependencyProvider> ?? dependencyProviders.ToList();
var included = new HashSet<DependencyProvider>(collection);
var includedTypes = new HashSet<Type>(collection.Select(x => x.GetType()));
var currentWorkingSet = new List<DependencyProvider>(collection);
while (true)
{
var candidates = currentWorkingSet.SelectMany(x => x.GetDependencies());
var typesToBeAdded = candidates.Where(x => !includedTypes.Contains(x)).Distinct().ToList();
if (typesToBeAdded.Any() == false)
break;
currentWorkingSet.Clear();
foreach (var type in typesToBeAdded)
{
includedTypes.Add(type);
var instance = CreateInstance(type);
included.Add(instance);
currentWorkingSet.Add(instance);
}
}
return BuildContainer(included);
}
and
TestDependencyProvider dependencyProvider = new TestDependencyProvider()
var builder = Compose(new[] { dependencyProvider });
Container = builder.Build();
The TestDependencyProvider is created for each test and contains moqed instances. It registers those mocks and x.GetDependencies() uses the original container registrations i.e. container.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).AsClosedTypesOf(typeof(IAggregateBusinessRuleForEvent<,>));
The type I'm mostly interested in is one of implementations of IAggregateBusinessRuleForEvent<,>).
public class RuleA: IAggregateBusinessRuleForEvent<AEvent, Something>
{
private readonly IDependency _dependency;
public RejectCompanyNameRule(IDependency dependency)
{
_dependency = dependency;
}
}
So even though I create this container again that RuleA is still there and all of my test are using same instance with same _dependency :/
It's still not entierly clear why code looks how it looks, I'm trying to understand it by adding tests...
------- EDIT 2
Following Jimmy's advice I've implemented a sample using Update me
public interface IExample<T>
{
void Hello();
}
public interface IExampleDependecy
{
void SaySomething();
}
public class Example : IExample<string>
{
private IExampleDependecy _dependecy;
public Example(IExampleDependecy dependecy)
{
_dependecy = dependecy;
}
public void Hello()
{
Console.WriteLine("Hello");
_dependecy.SaySomething();
}
}
[TestMethod]
public void T()
{
// first test
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).AsClosedTypesOf(typeof(IExample<>));
var mockA = new Moq.Mock<IExampleDependecy>();
mockA.Setup(d => d.SaySomething()).Callback(() => Console.WriteLine("A"));
builder.RegisterInstance(mockA.Object).SingleInstance();
var container = builder.Build();
var sample1 = container.Resolve<IExample<string>>();
sample1.Hello();
// new test using same container
var updater = new ContainerBuilder();
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).AsClosedTypesOf(typeof(IExample<>));
var mockB = new Moq.Mock<IExampleDependecy>();
mockB.Setup(d => d.SaySomething()).Callback(() => Console.WriteLine("B"));
builder.RegisterInstance(mockB.Object).SingleInstance();
updater.Update(container); // overwrites existing registrations
var sample2 = container.Resolve<IExample<string>>();
sample2.Hello();
}
and result is:
Hello
A
Hello
A
Autofac by default overrides previous registrations with subsequent ones. That means you don't have to do anything special apart from updating container with your new instance:
var builder = new ContainerBuilder();
builder.RegisterInstance(new Sample("A")).SingleInstance();
var container = builder.Build();
var sample = container.Resolve<Sample>();
// do your test
...
// new test using same container
var updater = new ContainerBuilder();
updater.RegisterInstance(new Sample("B")).SingleInstance();
updater.Update(container); // overwrites existing registrations
var sample = container.Resolve<Sample>(); // returns "B"

Solution for "XamlInjector–Cannot create unknown type errors" does not work

In unit test, i passed the assembly of Custom Activity to the ctor as the local assembly
var xamlInjector = new XamlInjector("CreditAtRenewalFlow.xaml", typeof(CreateFollowUp).Assembly);
CreateFollowUp is a AsynCodeActivity
I got error "'Unexpected 'PROPERTYELEMENT' in parse rule 'Element ::= . EmptyElement | ( StartElement ElementBody ).'.' Line number '2' and line position '4'." at execution of the following line
var host = WorkflowInvokerTest.Create(xamlInjector.GetActivity());
The sample of the unit test is [TestMethod]
[DeploymentItem(#"src\ProcessFlows\Activity1.xaml")]
public void Activity1Test()
{
var xamlInjector = new XamlInjector("Activity1.xaml", typeof(CreateFollowUp).Assembly);
xamlInjector.ReplaceAll(typeof(CreateFollowUp), typeof (MockCreateFollowUp));
var mockExternalServiceManager = new Mock<IExternalServices>();
mockExternalServiceManager.Setup(x => x.CreateFollowUp()).Verifiable();
var host = WorkflowInvokerTest.Create(xamlInjector.GetActivity());
dynamic parameterValues1 = new WorkflowArguments();
parameterValues1.value1 = mockExternalServiceManager.Object;
IDictionary<string, object> dictionary = host.TestActivity();
}
And the CreateFollowUp is given below
public sealed class CreateFollowUp : AsyncCodeActivity
{
[RequiredArgument]
public InArgument ExternalServices { get; set; }
protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback,
object state)
{
Action createFollowUp = this.ExternalServices.Get(context).CreateFollowUp;
context.UserState = createFollowUp;
return createFollowUp.BeginInvoke(callback, state);
}
protected override void EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
var createFollowUp = context.UserState as Action;
if (createFollowUp == null)
{
throw new ArgumentNullException("The AsyncState of the IAsyncResult was not of the type
ExternalServices.AsyncCreateFollowUp.", (Exception)null);
}
createFollowUp.EndInvoke(result);
}
}
try to modify source code of the activity. Change "xmlns:local="clr-namespace:Activity1" to xmlns:local="clr-namespace:Activity1;assembly=Activity1".
include the assembly in namespaces references (use the correct assembly name)