Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Monday, November 7, 2011

Log4net in a not-.NET application

Hi everyone,

So I've moved on to a couple of other projects (Recordings is now live and complete enough). One such project is an old legacy VB6 application that I'm extending with C# via COM interop.

The situation I have is this:
  • I would like to use Log4net in the C# code, compiled as DLLs and imported into the VB6  project
  • I would like to configure Log4net via an xml config file, but it won't have to change at runtime. 
So, here's how that's accomplished:

The log4net.config file is added as an embedded resource in the C# class library project. It looks like this:

<?xml version="1.0" encoding="utf-8" ?>

<log4net>
  <appender name="DebugFileAppender" type="log4net.Appender.RollingFileAppender">
    <file value="J:\Chris\Source\citysiege\main\logs\" />
    <appendToFile value="true" />
    <rollingStyle value="Date" />
    <maxSizeRollBackups value="30" />
    <datePattern value="yyyy-MM-dd'.txt'" />
    <staticLogFileName value="false" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/>
    </layout>
    <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
  </appender>

  <root>
    <level value="DEBUG" />
    <appender-ref ref="DebugFileAppender" />
  </root>
</log4net>

A static class method serves as a wrapper around the log4net library and an entry point to configure it:

            var assembly = Assembly.GetExecutingAssembly();
            var stream = assembly.GetManifestResourceStream("CitySiegeLogic.log4net.config");
            log4net.Config.XmlConfigurator.Configure(stream);

Simple right? Well, took a little while to figure out. Also, if the config file is in a subfolder be sure to add that to the path along with the namespace, so for example "CitySiegeLogic.logging.log4net" if its under /logging.

Sunday, June 19, 2011

Writing and testing a 2007 MS Word Add-in using NUnit, Moq, and the MVP pattern

Hey everyone,

Today I want to show you an approach to writing a testable UI. To do this I'm going to write a 2007 Microsoft Word Add-in using Microsoft's Visual Studio Tools for Office. The goal is to write an application level add-in and test it using NUnit and Moq.

 I'm going to design it around the Model-View-Presenter pattern: We'll have two interfaces: An IView, which will be an Office ribbon and contain no logic. Then we'll  have an IPresenter, which will handle all of the "UI logic" such as taking actions based on user dialog results etc.

Our Presenter won't actually have any domain logic in it: we'll be delegating that to another class (I'll explain that in a minute). This means that when we test it, we'll be doing behavior testing instead of testing for object states. This also means we'll be using Moq to setup our Mock domain objects and verifying that calls are made to them.

Of course it's important to note that this kind of testing involves some coupling between your tests and the implementation of the class under test, but I think it's acceptable since the Presenter is behavior based.

So what kind of add-in will we be doing? Well at first I was going to be boring and use a very contrived example. But then I came up with a nice domain-specific idea.

I figured why not do something chemistry related? That's always fun. So we're going to make an addition to the Word ribbon that allows the user to enter either a chemical formula or an entire reaction equation. When the user clicks the "Action" button, the add-in will either render the equation as an image and insert it, or if the user enters a single compound it will insert the molar mass at the cursor position.

Here's the user interface:


Don't worry about the actual logic behind rendering and molar mass calculation. I've already taken care of that using my chemical database program I wrote last year. Now of course I think the code is crap, but it still works and that's the main thing.

So let's get started by defining our interfaces. Our IPresenter will only contain a single method: Action() which returns void and expects no parameters. Our Ribbon will implement IView. To start with, we'll give IView two properties: MolarMass and EquationText:


IView.cs:
namespace Chemistry.UI
{
    public interface IView
    {
        double MolarMass
        {
            set;
        }
        string EquationText
        {
            get; 
        }
    }
}
IPresenter.cs:
namespace Chemistry.UI
{
    public interface IPresenter
    {
        void Action(); 
    }
}

In our first iteration we'll simply assume that the user-entered text is a compound and we want to calculate the molar mass of it. Let's write a simple test that will confirm our IPresenter implementation makes a call to our domain object (an instance of IFormulaParser):

Presenter.cs:
namespace Chemistry.UI
{
    public class Presenter : IPresenter
    {
        public void Action()
        {
            throw new NotImplementedException();
        }
    }
}
IFormulaParser.cs:
namespace Chemistry.UI
{
    public interface IFormulaParser
    {
        double MolarMass(string compound); 
    }
}
And now our test file, PresenterTests.cs:

using NUnit.Framework;
using Moq;
using Chemistry.UI; 
namespace Tests
{
    public class PresenterTests
    {
        private IPresenter _presenter;
        private Mock<IFormulaParser> _formulaParser; 

        [SetUp] 
        public void SetUp()
        {
            _presenter = new Presenter();
            _formulaParser = new Mock<IFormulaParser>();            
        }

        [TestCase] 
        public void Action_UserEntersCompound_CallsMolarMassMethod()
        {
            _presenter.Action(); 
            _formulaParser.Verify(parser => parser.MolarMass("O2")); 
        }
    }
}

So in our test class we initialize a new Presenter object and a mock FormulaParser. For now we've set the IFormulaPresenter to return a value of 32 when MolarMass("O2") is called. In our test case, we make sure that our FormulaParser is called correctly. Of course the test fails since Presenter doesn't do anything. Let's change it so that it uses the text entered by the user instead our hard-coded value.

using NUnit.Framework;
using Moq;
using Chemistry.UI; 
namespace Tests
{
    public class PresenterTests
    {
        private IPresenter _presenter;
        private Mock<IFormulaParser> _formulaParser;
        private Mock<IView> _view; 

        [SetUp] 
        public void SetUp()
        {
            _presenter = new Presenter();
            _formulaParser = new Mock<IFormulaParser>();            
            _view = new Mock<IView>(); 
        }

        [TestCase("O2",32.0)] 
        [TestCase("H2", 2.0)]
        [TestCase("C6H6",78.0)]
        public void Action_UserEntersCompound_CallsMolarMassMethod(string compound, double molarMass)
        {
            _view.Setup(view => view.EquationText).Returns(compound);
            _formulaParser.Setup(parser => parser.MolarMass(compound)).Returns(molarMass);                 

            _presenter.Action(); 

            _formulaParser.Verify(parser => parser.MolarMass(compound)); 
        }
    }
}


Now we've done a couple things. First, we've created a new mock IView. We also changed our test to accept parameters and set up the view's EquationText property with the compound string. Finally, we check again to make sure the presenter calls the FormulaParser.MolarMass method. Now let's make the Presenter pass the test.

public class Presenter : IPresenter
{
 private IFormulaParser _formulaParser;
 private IView _view;

 public Presenter(IView view)
 {
  _view = view;
  _formulaParser = new FormulaParser(); 
 }

 public void Action()
 {
  _view.MolarMass = _formulaParser.MolarMass(_view.EquationText); 
 }
}

Alright, so now the Presenter is using the IView's equation text property, calculating the molar mass, and setting the IView's MolarMass property to the result. Let's also update the test cases to verify that View's MolarMass property is also set:

[SetUp] 
public void SetUp()
{
 _view = new Mock<IView>();
 _formulaParser = new Mock<IFormulaParser>();                  
 _presenter = new Presenter(_formulaParser.Object, _view.Object);                  
}

[TestCase("O2",32.0)] 
[TestCase("H2", 2.0)]
[TestCase("C6H6",78.0)]
public void Action_UserEntersCompound_CallsMolarMassMethod(string compound, double molarMass)
{
 _view.Setup(view => view.EquationText).Returns(compound);
 _formulaParser.Setup(parser => parser.MolarMass(compound)).Returns(molarMass);  
              
 _presenter.Action(); 

 _formulaParser.Verify(parser => parser.MolarMass(compound));
 _view.VerifySet(view => view.MolarMass = molarMass); 
}

At this point, our test passes. And at this point if we implement IView in our Ribbon object, everything should work. So let's proceed and implement rendering equations as well. Let's start by writing a test to make sure our rendering object is called. To do thish we need to add our IEquationRenderer interface, which has a reference to System.Drawing:

public interface IEquationRenderer
{
 Image RenderEquation(string equation); 
}

And modify the Presenter constructor:

public Presenter(IEquationRenderer equationRenderer, IFormulaParser formulaParser,  IView view)
{
 _view = view;
 _formulaParser = formulaParser;
 _equationRenderer = equationRenderer; 
}

Finally add our test case:

[TestCase("H2 + O2 ----> H2O")]
public void Action_UserEntersEquation_CallsEquationRenderer(string equation)
{                        
 _view.Setup(view => view.EquationText).Returns(equation);            
 _presenter.Action();
 _equationRenderer.Verify(renderer => renderer.RenderEquation(equation));
 _view.VerifySet(view => view.EquationImage = It.IsAny<Image>()); 
}

An important note here: I wasn't able to mock the Image interface that we're passing around, so we're verifying that the IView gets its EquationImage property set to "any" Image object instead of a dummy Image that we would pass around normally.

If we make this test pass by just adding a call to our EquationRenderer, we could also still be calling the molar mass calculation which we don't want. So let's add another test that ensures that when we parse an equation, we don't try a molar mass calculation:

[TestCase("H2 + O2 ----> H2O")]
public void Action_UserEntersEquation_DoesNotTryMolarMassCalculation(string equation)
{
 _view.Setup(view => view.EquationText).Returns(equation);
 _presenter.Action();
 _formulaParser.Verify(parser => parser.MolarMass(It.IsAny<string>()), Times.Never()); 
}

This test will fail because we need some conditional logic to differentiate compounds and equations. Let's do this by adding a method to IFormulaParser:

bool IsEquation(string text); 

Let's set this up in our equation tests to return true by adding this setup line to our two test cases:

_formulaParser.Setup(parser => parser.IsEquation(equation)).Returns(true); 

The actual implementation will just check for the presence of "---->," but that could always change. Now we can modify the Presenter to take this into account:

public void Action()
{
 if (_formulaParser.IsEquation(_view.EquationText))
 {
  _view.EquationImage = _equationRenderer.RenderEquation(_view.EquationText); 
 }
 else
 {
  _view.MolarMass = _formulaParser.MolarMass(_view.EquationText);
 }            
}

And now our tests pass. At this point, the rest of the work is implementation details. Here's an example of the final result:

The important thing to note with this approach is that we've created an extremely testable UI layer. Since all of the logic is in the Presenter class, we can test all aspects of the UI. This becomes even more exciting when your UI logic involves the user making decisions by answering prompts and responding to dialogs. You could for example wrap a call to MessageBox.Show in an IView DisplayMessage() method that returns a DialogResult. This would allow you to test the Presenter and just mock the IView.

Anyway, just for reference, the full source code of this add-in is on my website. Apologies in advance for the weird project structure, the Test project is under the "Tests" folder. The solution uses Visual Studio 2010.

Monday, April 4, 2011

More on chemical structure drawing with C#, TDD, and a dash of algorithms

Progress 

So recently I've been working on implementing a chemical structure drawing tool in C# using WinForms. Along the way I've been adhering to TDD (test-driven development), and it's been a pretty positive experience. I've managed to avoid using the debugger and have a very clear separation between UI and logic code.

The "industry standard" for representing chemical structures is to represent atoms as nodes and bonds as edges of an undirected graph. Although atoms and bonds can have an extensive set of details, I've been sticking to a set of simple properties in the meantime. So far the back-end of the program is fairly developed, and on the GUI front-end I have basic functionality such as creating and deletion of atoms/bonds.

Quirks 

There's always a random quirk that you end up having to implement, in my case it was allowing the user to click on a bond. Now, a bond is just a connection between two (x,y) points, so to test for a mouse click on a bond we need to test the distance of the mouse position from the line segment representing the bond.

Oddly enough, I had a working C# solution to that problem awhile ago (it was a pain to find one too, adapted from this stackoverflow question!)

But the other 'quirk' is a lot more interesting than geometry, and it involves generating a string of text that represents a chemical compound. One of the important formats to do this is called SMILES, and I would eventually like the program to be able to generate and/or parse it.

The problem? The format is kind of complicated and hairy, and has to account for a lot of different chemical properties. So for the moment writing a parser is a task in itself.

Generation using depth-first searching

Luckily, generating the SMILES code is easier. The most simplistic way is to simply do a depth-first search through the graph, while identifying nodes that appear twice (these will be part of rings). This algorithm will generate "correct" but not canonical or normalized SMILES strings, although the programs I've used will all parse them.  To get more involved requires identifying rings, taking into account other bond/atom properties, and all kinds of hairy stuff.

In fact, in the big chemistry libraries (in Java for example), the code to do this is very long and hard to understand. At least, I can't understand it. So for the moment I'm stuck trying to reinvent the wheel, but starting a whole lot simpler.

And that's all for today. Check back next time for more progress and other fun topics.

Thursday, February 17, 2011

What happens when you just set a Stream position to zero (C#)

This morning I was fixing a few bugs which I had found in HTML Combiner and I noticed a few of my unit tests that loaded configuration files were failing. They were using a MemoryStream object so that they read from a string instead of the file system. The first thing I thought was that it was just a problem reading from a string, and wouldn't happen when reading from an actual file.

Of course then I ran the program and notice that when I loaded the configuration file for my website, my tags were showing up twice. After setting up NUnit to run in visual studio and stepping through the debugger, it was in fact reading the file multiple times.

After spending about an hour wondering what was wrong, I casually glanced at a few links on google about resetting a stream position (which I do at the beginning of the method). Finally, I made it to the StreamReader.DiscardBufferedData example code on the MSDN library website.

If you change the stream position using Seek, the actual position of the buffer is now out of sync. So you have to call DiscardBufferedData in order to force the stream to go to the desired position. After I added this line everything worked once again:

sr.DiscardBufferedData();          // where sr is a StreamReader
sr.BaseStream.Seek(0, SeekOrigin.Begin);

This made me glad that I've been adding unit tests to catch things like this -- I might have overlooked the problem the tests weren't failing. Another similar incident happened a few days ago when a small bug was introduced after I made a change, the bug would result in the build path not being loaded from a configuration file. The actual problem looked pretty innocent, it would have taken time to isolate the cause. However, I was able to catch it because the test failed shortly after I had made the change.

Tuesday, February 15, 2011

Unit testing a method that makes heavy use of FileStream (C#)

While working on the HTML Combiner, I ran into a situation where I was trying to test a method that wrote a configuration file. This method makes heavy use of FileStream, and so the resulting test would have been coupled to the filesystem. This seems like a common issue you would run into, and there are a few ways to approach the unit test for such a method:
  1. Allow the filesystem dependency
  2. Create an "IDataSource" interface and make an implementation that wraps the FileStream object
  3. Instead of using FileStream, use its parent, Stream, in the method you're trying to test
Option (1) is out since that's exactly what we're trying to avoid! Allowing the dependency on the file system is a bad idea, because it allows anything that can go wrong with file IO to potentially fail your unit test at an unpredictable time. In addition, if you're writing to files, you have to worry about cleaning up so your tests don't read the file of a previous test run.

Option (2) seems like a good idea because you can stub the IDataSource interface in the unit test. In fact, I probably will do this later on (I admit, I was rushed for time!). This means that you will have to change your method's code to use the interface instead of changing "FileStream" to "Stream," but it's a more elegant solution that does not depend on Stream at all.

Option (3) is the one I went with, and isn't a terrible solution. By using a Stream object in the target method, you no longer depend on the FileStream (and consequently the file system). In your test for example, you can pass in a MemoryStream which contains a test "file" whose contents are in a string you declare. However, I did encounter some disadvantages:
  • You still have a dependency on Stream, instead of using a stub
  • You have to specify the encoding your string uses in order to create a MemoryStream out of it
  • Creating and writing to the MemoryStream is not painless
Well, we still achieve decoupling from the filesystem, which was the main goal. However, in the future, I will probably switch to an "IDataSource" interface and use that. This way, we get total independence from Stream and we could also write an implementation that, say, reads/writes an SQL database.