Showing posts with label Glass. Show all posts
Showing posts with label Glass. Show all posts

Tuesday, June 30, 2015

Unit Testing in Sitecore

Unit testing seems to be one of those topics that everyone generally agrees is a Good Idea, but when no one is looking it becomes fantastically easy to justify to oneself why for this project at this particular time it's ok to forgo unit tests.

My purpose here isn't to convince (guilt) you into doing unit tests. Rather, I'd like to demonstrate that actually implementing them can be trivially easy. Now, of course, anyone can write a unit test that is easy but does it add value? Well, that'll depend upon you, of course. My advice is target the hot spots in your code first and anytime you encounter a bug write a unit test that validates the bug is resolved. Aiming for 100% code coverage is admirable but don't let the perfect be the enemy of the good. Ok—enough preaching philosophizing!

Tools

First a word about tools. I favor Glass (version 3 for the purpose of this blog post) as my Sitecore ORM; this will have some ramifications for unit tests. As far as a unit testing framework, I have settled upon xUnit. Is this terribly important? Not especially. NUnit is quite popular and powerful. The designers of NUnit actually wrote xUnit. You can view their reasons for doing so here. Regardless of which framework you select, most of what I document here will still apply, the main difference is the syntax. For mocking, I have come to really like Sitecore.FakeDb. It's an amazing product. Add a NuGet package to your project and you suddenly have to power to run all of Sitecore's API without the need of a website. There are other Sitecore mocking tools out there, but I highly recommend this one. Finally, for a bit of syntactic sugar I suggest Fluent Assertions. Again, simply add the NuGet to your project and your assertion statements will read very nearly like English.

Some Lessons Learned

  • I don't need FakeDb for data mocking so long as I am working solely with Glass object. Since every Glass-mapped class is an implemenation of an interface, my mock test data can also simply implement that interface.
  • FakeDb is convenient, nonetheless, because it allows Glass's CreateFakeItem method to 'just work' without having to go the extra length of providing a testing database along with hand-(re)creating all of the config settings necessary to connect Sitecore's API layer to a data provider. This means that for very simple API calls you could avoid mocking with FakeDb and do it all through Glass. In practice, however, I find FakeDb to be so fast as to leave me wonder if there is any advantage to this.'
  • I can (if I want) cast from a FakeDb item to a Glass object. Nathanael Mann warns against this practice for performance reasons and because it blurs the line between unit testing and integration testing. In fairness, I am over-simplifying his thesis a bit, nonetheless, for me, the raw convenience of being able easily to mock Sitecore data is simply too powerful to ignore. As far as performance goes, once Glass's context has been created (~800ms hit) unit tests involving Glass run in less than 10ms even when casting. 10 seconds per 1000 tests? I can accept that.

Everybody Loves an Example


namespace MyPOCO.Tests.Data.Domain
{
    public class My_POCO_Tests
    {
        public class DoesQueryStringMatchMethod
        {

            public static DbTemplate GetMyPOCOTemplate()
            {
                return new DbTemplate(IMy_POCOConstants.TemplateName, IMy_POCOConstants.TemplateId)
                {
                    new DbField(IMy_POCOConstants.Query_String_Value_To_MatchFieldName, 
                        IMy_POCOConstants.Query_String_Value_To_MatchFieldId)
                };
            }
             
            [Fact]
            public void RequestedUrlHasUpperCaseValues()
            {
                //arrange
                string requestedUrl = "http://www.google.com?foo=bar&color=RED";
                GlassMapperContext.CreateContext();
                using (var db = new Db
                {
                    FakeDbHelper.GetMyPOCOTemplate(),
                    new DbItem("test", ID.NewID, IMy_POCOConstants.TemplateId)
                    {
                        {IMy_POCOConstants.Query_String_Value_To_MatchFieldName, requestedUrl}
                    }
                })
                {
                    global::Sitecore.Data.Items.Item home = db.GetItem("/sitecore/content/test");
                    My_POCO poco = home.GlassCast<My_POCO>();

                    //act
                    bool result = poco.DoesQueryStringMatch(requestedUrl);

                    //assert
                    result.Should().BeTrue();
                }
            }
        }
    }
}

So, what does this code demonstrate? It shows a Glass-mapped object that has a method I wish to unit test. The method is named DoesQueryStringMatch. Presumably, the method compares the requested URL against a field value and returns a boolean. Of course, a more realistic and more useful test would be against a method that had a more complicated job to do, but for purposes of illustrating the technique we'll stick with a contrived example.

 I could have mocked my Glass object without the need for FakeDb, and I do need to create my Glass context (that's the GlassMapperContext.CreateContext() method call.) Once that work is done, however, I am free and clear for all further unit tests where I may have need to test against Sitecore items—example: an action for the rules engine. I leverage the fact that Glass maintains constants about my template and its fields. Necessary? No, but very useful if I have to create an item with a complicated structure. Creating the Glass context is simple enough. I just replicate the code called in the Start() method of GlassMapperSc.cs.


Friday, April 3, 2015

How to Map Sitecore Rules Field with Glass and TDS

tl;dr Copy lines 246 and 247 from here. Regenerate your Glass classes. 

Today a colleague asked how to map the rules field from Sitecore with Glass Mapper using TDS and T4 templates. It just so happens that I'd recently worked on this problem, and I thought I would share it with others here.

The basic issue is that the glassv3item.tt template doesn't know how to deal with the Rules field. The GetGlassFieldByType method is responsible for assigning a type to mapped field. It does this with a switch statement. Our rules field is falling all the way through to the default case which maps the field to an object. We need to add a case for the field.Type value when it equals "rules".

What type will we map to though? On first pass I thought something like XDocument would make a lot of sense. Problem is that doesn't work. The value is always null. I took a look inside the Glass.Mapper.Sc.dll at what I believe is the code responsible for returning a value. It looks to me like the mapping code isn't fully implemented, and Glass relies on a generic method that simply returns a string value.


Not a big deal. We can work with this.

After you've modified the T4 template and regenerated your Glass classes, you should have a mapped property on your class of type string. I've found for my purposes this is perfect for my needs, but that didn't stop me from extending my partial class with an XDocument property...just in case.

public partial class GeneratedClass
{
    public XDocument RuleAsXDocument
    {
        get { return XDocument.Parse(this.Rule); }
    }
}

Tuesday, March 24, 2015

Solr + Glass = Castle Windsor Crashers?

(I know the title isn't technically true...don't judge me!)

I think it's safe to say most of us Sitecore developers are using some form of ORM these days, right? ...Right? :)

Of course you are, and – most likely – that means you are using Glass Mapper. Probably, you are also using Castle Windsor as your choice of Inversion of Control. You could use some other IoC, but there's a NuGet package that makes incorporating Castle Windsor + Glass into your Visual Studio solution quite easy.

So what if you read my series on Solr and were inspired to use it for Sitecore? Solr also requires an IoC. As I mentioned here, you may choose from Castle Windsor, AutoFac, Ninject, StructureMap, and Unity. It seems only natural to stick with the same IoC as Glass. Common sense says don't add more moving parts than necessary.

And this is why common sense isn't always common or sensible. The moment you deploy your Glass dependent (and thus Castle Windsor dependent) code to your Sitecore instance, you are going to be treated to some ugly YSODs. The issue is that Glass wants to use a higher version of Castle Windsor (3.2) than your Solr-enabled Sitecore instance; it wants version 3.1.

Luckily the fix is relatively painless. We are going to instruct .NET to redirect bindings of earlier versions of Castle.Core and Castle.Windsor to our later version. All you need to do is add the following section to your web.config: