I have a WPF app running, which needs all operations that affect the UI to be on the UI Thread. WPF also provides a Dispatcher class that handles this - so I extracted that into a dependency.
public interface UIActionExecutor
{
void Do(Action action);
}
So in my production code, I use an exported implementation which delegates to the WPF Dispatcher. I'm using MEF for DI.
Now the problem, in my acceptance tests, I need to replace the part / object in the container that responds to UIActionExecutor by a Mock. So I need to remove ExecutorUsingWpfDispatcher from my container and add MockUIActionExecutor in its place. This sounds pretty simple (if I was not using MEF)... but my searching skills haven't helped me find an answer as to how to do this with the MEF container ?
Update:
If anyone wants to know why/how the solution works - read Glenn Block's blog post#2. This is what I ended up using
var defaultExportProvider = new CatalogExportProvider(__defaultCatalog);
var catalogOfMocks = new AssemblyCatalog(assemblyExportingMocks);
// order of params important (precedence left to right)
__container = new CompositionContainer(catalogOfMocks, defaultExportProvider);
defaultExportProvider.SourceProvider = __container
A DI container is responsible for wiring everything together.
A unit test is responsible for testing a single unit of code in isolation. Mocks are used to replace dependencies. So in principle a DI container should not be used in a unit test. It contradicts the definition of "unit test".(¹)
However, I can certainly understand that you might want to do automated integration tests in addition to unit tests, and you might want to use MEF yet replace certain MEF parts in such a test. You can do that like this:
// first set up the main export provider
var mainCatalog = new AggregateCatalog(...);
var mainExportProvider = new CatalogExportProvider(mainCatalog);
// now set up a container with mocks
var mockContainer = new CompositionContainer();
mockContainer.ComposeExportedValue<IFoo>(fooMock);
mockContainer.ComposeExportedValue<IBar>(barMock);
// use this testContainer, it will give precedence to mocks when available
var testContainer = new CompositionContainer(mockContainer, mainExportProvider);
// link back to the testContainer so mainExportProvider picks up the mocks
mainExportProvider.SourceProvider = testContainer;
(¹)Judging from your blog, I'm sure you already know this. But others will also read this answer, so I wanted to be clear about the term "unit test".
Could not get the accepted solution to work. Below code should work and precedence is described in the documentation for AggregateExportProvider.
var mainContainer = new CompostionContainer();
mainContainer.ComposeExportedValue<IFoo>(new Foo() {Test = 1});
var mockContainer = new CompositionContainer();
mockContainer.ComposeExportedValue<IFoo>(new Foo() {Test = 2});
var aggregateExportProvider = new AggregateExportProvider(
mockContainer, // IFoo in this container takes precedence
mainContainer);
IFoo foo = aggregateExportProvider.GetExportedValue<IFoo>();
Console.WriteLine(foo.Test); // Outputs: 2
Related
I am new to NLog, but I think I have got a good understand of how it works in the last hours.
After digging deeper into NLog API, several questions about Logging Rules come up. One of them is:
How can I remove a rule by name (using LoggingConfiguration.RemoveRuleByName()) that I have added programmatically by LoggingConfiguration.AddRule() before?
LoggingConfiguration.AddRule() does not provide an argument to set the LoggingRule.RuleName.
LoggingConfiguration.AddRule() does not take a LoggingRule object.
I don't want to check every rule in the LoggingConfiguration.LoggingRules collection, because this would mean checking them by content, because I cannot set a name.
While writing the question, I found the solution, which I want to share here.
The LoggingConfiguration.LoggingRules collection is a IList<LoggingRule> and thus supports Add(), Clear(), etc.
Therefore it is possible to add LoggingRule objects directly into this list. The LoggingRule object can be removed again by IList<>.Remove(), and, if it has a name, by LoggingConfiguration.Remove().
Example for adding named rule:
var loggingRule1 = new NLog.Config.LoggingRule ();
loggingRule1.RuleName = nameof (loggingRule1); // RuleName can also be set in constructor.
loggingRule1.LoggerNamePattern = "*";
loggingRule1.SetLoggingLevels (NLog.LogLevel.Info, NLog.LogLevel.Error);
loggingRule1.Targets.Add (consoleTarget);
loggingConfiguration.LoggingRules.Add (loggingRule1);
var loggingRule2 = new NLog.Config.LoggingRule ("*", NLog.LogLevel.Trace, NLog.LogLevel.Trace, consoleTarget) { RuleName = "loggingRule2" };
loggingConfiguration.LoggingRules.Add (loggingRule2);
logFactory.ReconfigExistingLoggers ();
// or, if config was not yet set to logFactory: logFactory.Configuration = loggingConfiguration;
Example for removing named rule:
loggingConfiguration.RemoveRuleByName (nameof (loggingRule1));
logFactory.ReconfigExistingLoggers ();
IMHO the API is poorly documented. I will suggest some more comprehensive descriptions.
I have a function that creates a user, stores in the database and subscribes it to a Mailchimp list.
I have a unit test that tests this function.
Now I do want to test this function, but I dont want the 'mocked' user to be added to the mailinglist.
Is there a way to partly exclude code execution when a function is run in a unit test mode?
So for example I have this function (simplyfied)
public async Task<CreateUserResponse> Create(CreateUserRequest createRequest){
//Save user to database
var encryptedPassword = encryptor.EncryptPassword(createRequest.Password, salt);
var user = new UserDomain(){
EmailAddress = createRequest.EmailAddress,
Password = encryptedPassword,
Salt = salt
}
_dbContext.Users.Add(user);
//Subscribe to mailing list
var mailChimpAdapter = new MailChimpAdapter(_configuration);
mailChimpAdapter.Subscribe(user);
return new CreateUserResponse(user);
}
Now I want to run a unit test to test that function but without subscribing it.
Best I can think of is using a variable in the config file and read it out inside the function. But maybe there is a better way?
One way is to extract an interface from MailChimpAdapter (say, IMailChimpAdapter) and then use it to mock the constructor and the subscribe method. You can use a library like Moq.
Check this for a quick intro :
I just found out about NRefactory 5 and I would guess, that it is the most suitable solution for my current problem. At the moment I'm developing a little C# scripting application for which I would like to provide code completion. Until recently I've done this using the "Roslyn" project from Microsoft. But as the latest update of this project requires .Net Framework 4.5 I can't use this any more as I would like the app to run under Win XP as well. So I have to switch to another technology here.
My problem is not the compilation stuff. This can be done, with some more effort, by .Net CodeDomProvider as well. The problem ist the code completion stuff. As far as I know, NRefactory 5 provides everything that is required to provide code completion (parser, type system etc.) but I just can't figure out how to use it. I took a look at SharpDevelop source code but they don't use NRefactory 5 for code completion there, they only use it as decompiler. As I couldn't find an example on how to use it for code completion in the net as well I thought that I might find some help here.
The situation is as follows. I have one single file containing the script code. Actually it is not even a file but a string which I get from the editor control (by the way: I'm using AvalonEdit for this. Great editor!) and some assemblies that needs to get referenced. So, no solution files, no project files etc. just one string of source code and the assemblies.
I've taken a look at the Demo that comes with NRefactory 5 and the article on code project and got up with something like this:
var unresolvedTypeSystem = syntaxTree.ToTypeSystem();
IProjectContent pc = new CSharpProjectContent();
// Add parsed files to the type system
pc = pc.AddOrUpdateFiles(unresolvedTypeSystem);
// Add referenced assemblies:
pc = pc.AddAssemblyReferences(new CecilLoader().LoadAssemblyFile(
System.Reflection.Assembly.GetAssembly(typeof(Object)).Location));
My problem is that I have no clue on how to go on. I'm not even sure if it is the right approach to accomplish my goal. How to use the CSharpCompletionEngine? What else is required? etc. You see there are many things that are very unclear at the moment and I hope you can bring some light into this.
Thank you all very much in advance!
I've just compiled and example project that does C# code completion with AvalonEdit and NRefactory.
It can be found on Github here.
Take a look at method ICSharpCode.NRefactory.CSharp.CodeCompletion.CreateEngine. You need to create an instance of CSharpCompletionEngine and pass in the correct document and the resolvers. I managed to get it working for CTRL+Space compltition scenario. However I am having troubles with references to types that are in other namespaces. It looks like CSharpTypeResolveContext does not take into account the using namespace statements - If I resolve the references with CSharpAstResolver, they are resolved OK, but I am unable to correctly use this resolver in code completition scenario...
UPDATE #1:
I've just managed to get the working by obtaining resolver from unresolved fail.
Here is the snippet:
var mb = new DefaultCompletionContextProvider(doc, unresolvedFile);
var resolver3 = unresolvedFile.GetResolver(cmp, loc); // get the resolver from unresolvedFile
var engine = new CSharpCompletionEngine(doc, mb, new CodeCompletionBugTests.TestFactory(resolver3), pctx, resolver3.CurrentTypeResolveContext );
Update #2:
Here is the complete method. It references classes from unit test projects, sou you would need to reference/copy them into your project:
public static IEnumerable<ICompletionData> DoCodeComplete(string editorText, int offset) // not the best way to put in the whole string every time
{
var doc = new ReadOnlyDocument(editorText);
var location = doc.GetLocation(offset);
string parsedText = editorText; // TODO: Why there are different values in test cases?
var syntaxTree = new CSharpParser().Parse(parsedText, "program.cs");
syntaxTree.Freeze();
var unresolvedFile = syntaxTree.ToTypeSystem();
var mb = new DefaultCompletionContextProvider(doc, unresolvedFile);
IProjectContent pctx = new CSharpProjectContent();
var refs = new List<IUnresolvedAssembly> { mscorlib.Value, systemCore.Value, systemAssembly.Value};
pctx = pctx.AddAssemblyReferences(refs);
pctx = pctx.AddOrUpdateFiles(unresolvedFile);
var cmp = pctx.CreateCompilation();
var resolver3 = unresolvedFile.GetResolver(cmp, location);
var engine = new CSharpCompletionEngine(doc, mb, new CodeCompletionBugTests.TestFactory(resolver3), pctx, resolver3.CurrentTypeResolveContext );
engine.EolMarker = Environment.NewLine;
engine.FormattingPolicy = FormattingOptionsFactory.CreateMono();
var data = engine.GetCompletionData(offset, controlSpace: false);
return data;
}
}
Hope it helps,
Matra
NRefactory 5 is being used in SharpDevelop 5. The source code for SharpDevelop 5 is currently available in the newNR branch on github. I would take a look at the CSharpCompletionBinding class which has code to display a completion list window using information from NRefactory's CSharpCompletionEngine.
I want to unit-test if my kernel-module has all bindings set to the right target. To easiest way I found was to create a kernel with the module loaded, get every bound-type and check if it is the right one:
this.kernel = new StandardKernel(new MainKernelModule());
Assert.That(this.kernel.Get<IMyClass>() is MyClass);
But some classes depends on a connection to a server, which shouldn't be used in my unit-test. Thats why this classes can't be created by the kernel in the unit-test-environment.
My Question: How can I get the target class of a IBinding?
var module = new MainKernelModule();
var kernel = new StandardKernel(module);
foreach (IBinding binding in module.Bindings)
{
// if (binding.BindingTarget is MyClass)
// Debug.WriteLine("Yeah");
}
I hope someone could help me. Unfortunately I found nothing with google.
Thanks in advance.
You can't or can you tell me what's the target class of
Bind<IFoo>().ToMethod(ctx=> IsItSunny() ? New SunnyFoo() : BadWeatherFoo())
What we do usually is not to test the bindings directly. But to write integration tests, where we replace the interface classes to other systems e.g DB access or web services by mocks and test the system functionality. this detects almost all binding problems. The small risk of wrong bindings to the foreign systems is detected realy fast when you do the manual integration tests.
I have started using a TDD approach to develop a small app that reads data from Excel files. Using a repository pattern type approach I have come to a hurdle which baffles me.
In order to read the Excel files, I am using the OpenXml-SDK. Now typically reading from an Excel file using the SDK requires several if not more steps to actually get the values you want to read.
The approach I have taken thus far is reflected in the following test and accompanying function.
[Test]
public void GetRateData_ShouldReturn_SpreadSheetDocument()
{
//Arrange
var fpBuilder = new Mock<IDirectoryBuilder>();
fpBuilder.Setup(fp => fp.FullPath()).Returns(It.IsAny<string>());
var doc = new Mock<IOpenXmlUtilities>();
doc.Setup(d => d.OpenReadOnlySpreadSheet(It.IsAny<string>()))
.Returns(Mock.Of<SpreadsheetDocument>());
swapData = new SwapRatesRepository(fpBuilder.Object, doc.Object);
//Act
var result = swapData.GetRateData();
//Assert
doc.Verify();
fpBuilder.Verify();
}
public class SwapRatesRepository: IRatesRepository<SwapRates>
{
private const string SWAP_DATA_FILENAME = "DATE_MKT_ZAR_SWAPFRA1.xlsx";
private IDirectoryBuilder builder;
private IOpenXmlUtilities openUtils;
public SwapRatesRepository(IDirectoryBuilder builder)
{
// TODO: Complete member initialization
this.builder = builder;
}
public SwapRatesRepository(IDirectoryBuilder builder,
IOpenXmlUtilities openUtils)
{
// TODO: Complete member initialization
this.builder = builder;
this.openUtils = openUtils;
}
public SwapRates GetRateData()
{
// determine the path of the file based on the date
builder.FileName = SWAP_DATA_FILENAME;
var path = builder.FullPath();
// open the excel file
using(SpreadsheetDocument doc = openUtils.OpenReadOnlySpreadSheet(path))
{
//WorkbookPart wkBookPart = doc.WorkbookPart;
//WorksheetPart wkSheetPart = wkBookPart.WorksheetParts.First();
//SheetData sheetData = wkSheetPart.Worksheet
// .GetFirstChild<SheetData>();
}
return new SwapRates(); // ignore this class for now, design later
}
}
However, the next steps after the spreadsheet is open would be to actually start interrogating the Excel object model to retrieve the values. As noted above, I making use of mocks for anything open xml related. However, in some cases the objects can't be mocked(or I don't know how to mock them since they are static). That gave rise to IOpenXmlUtilities which are merely simple wrapper calls into the OpenXml-SDK.
In terms of design, we know that reading data from excel files is a short term solution (6-8 months), so these tests only affect the repository/data access for the moment.
Obviously I don't want to leave the TDD approach(as tempting as it is), so I am looking for advise and guidance on how to continue my TDD endeavours with the OpenXml SDK. The other aspect relates to mocking - I am confused as to when and how to use mocks in this case. I don't want to unknowingly writes tests that test the OpenXml-SDK.
*Side note: I know that the SOLIDity of my design can be improved but I leaving that for now. I have a set of separate tests that relate to the builder object. The other side effect that may occur is the design of an OpenXML-SDK wrapper library.
Edit: Unbeknown at the time, by creating the OpenXML-SDK wrappers for the OpenXML-SDK, i have used a design pattern similar (or exact) called the Adaptor pattern.
If you can't mock it and can't create a small unittest, it might be better to take it to a higher level and make a scenario test. You can use the [TestInitialize] and [TestCleanup] methods to create a setup for the test.
using Pex and Moles might be another way to get it tested.