Unit Testing IPublishedContent when using GetPropertyValue
We have a number of classes that use INode, and we are just in the process of converting them to IPublishedContent. As part of this, we are updating our unit tests accordingly.
We use Moq to create a mocked up IPublishedContent, and add a mocked IPublishedContentProperty to its properties collection.
The coed we are testing retrieves a property value from IPublishedContent using GetPropertyValue.
I was expecting this to return the value of the IPublishedContentProperty, but wrapepd in a null check. However, it seems to call out to "PublishedContentHelper.GetDataType" to get the GUID of the data type for the property. In turn, this calls out to applicationContext.Services.ContentTypeService, and at this point through a null reference exception because there is no application context.
I believe there is an Umbraco project designed to help with unit testing. I am a little loathe to have to create a dummy application context and wire it up because this means my unit tests are going to have to be very aware of the Umbraco internals and I think this is going to make them hard to read and potentially a bit fragile. Whereas with using an interface it feels like this shouldn't be necessary.
Is there an easy way to do this? I realise we could just change our code so that it doesn't use the GetPropertyValue extension method but it feels like we are reinventing the wheel.
And out of curiosity, why does it need to do this when the property does include a value? (So if we did decide to write our own - what would we be missing?)
I was trying to convert something from using the old INode interface to IPublishedContent. After I battled with this for a bit I decided not to bother, so just left the code as INode.
The only other ways I can think of are looking at the test version of the application context or not using GetPropertyValue. I did wonder if a GetPropertyValueWithoutHittingDatabase<T> extension of my own might work. Presumably the DB hit is needed for something though. (?)
I guess it might be possible to use something like MS Fakes if your Visual Studio license covers yo ufor it. I think it allows you to mock up things that otherwise can't be mocked up, but I've not tried it.
It's a real shame - as it's so close to being good.
Andy, thanks for the info! I will look into MS Fakes. No luck with mocks from Moq so far. I was able to mock IPublishedContent but you can't mock extension methods, so GetPropertyValue was giving me a hard time.
var property = node.GetProperty("property");
if (property.HasValue)
{
var myInt = Convert.ToInt32(propertyValue);
}
In your Unit Test:
//Arrange
var intProperty = new Mock<IPublishedProperty>();
intProperty.SetupGet(p => p.HasValue).Returns(true);
intProperty.Setup(p => p.Value).Returns(1024);
intProperty.Setup(y => y.Value).Returns(intProperty.Object.Value);
var node = new Mock<IPublishedContent>();
node.Setup(y => y.GetProperty("something")).Returns(intProperty.Object);
contentQ.Setup(x => x.TypedContentSingleAtXPath("//NodeDocType")).Returns(node.Object);
//Act
var actualNode =myclass.MyMethod();
//Assert
actualNode .Verify(p => p.GetProperty(It.IsAny<string>()), Times.AtLeastOnce);//make sure that the value Has Value check is performed
intProperty.Verify(p => p.Value, Times.AtLeastOnce);//make sure that the value is assigned
Unit Testing IPublishedContent when using GetPropertyValue
We have a number of classes that use INode, and we are just in the process of converting them to IPublishedContent. As part of this, we are updating our unit tests accordingly.
We use Moq to create a mocked up IPublishedContent, and add a mocked IPublishedContentProperty to its properties collection.
The coed we are testing retrieves a property value from IPublishedContent using GetPropertyValue.
I was expecting this to return the value of the IPublishedContentProperty, but wrapepd in a null check. However, it seems to call out to "PublishedContentHelper.GetDataType" to get the GUID of the data type for the property. In turn, this calls out to applicationContext.Services.ContentTypeService, and at this point through a null reference exception because there is no application context.
I believe there is an Umbraco project designed to help with unit testing. I am a little loathe to have to create a dummy application context and wire it up because this means my unit tests are going to have to be very aware of the Umbraco internals and I think this is going to make them hard to read and potentially a bit fragile. Whereas with using an interface it feels like this shouldn't be necessary.
Is there an easy way to do this? I realise we could just change our code so that it doesn't use the GetPropertyValue extension method but it feels like we are reinventing the wheel.
And out of curiosity, why does it need to do this when the property does include a value? (So if we did decide to write our own - what would we be missing?)
Thanks!
John
Good question, just ran into the same problem. Have you found a (nice) workaround for this?
Not really, I'm afraid, I just gave up. :(
I was trying to convert something from using the old INode interface to IPublishedContent. After I battled with this for a bit I decided not to bother, so just left the code as INode.
The only other ways I can think of are looking at the test version of the application context or not using GetPropertyValue. I did wonder if a GetPropertyValueWithoutHittingDatabase<T> extension of my own might work. Presumably the DB hit is needed for something though. (?)
I guess it might be possible to use something like MS Fakes if your Visual Studio license covers yo ufor it. I think it allows you to mock up things that otherwise can't be mocked up, but I've not tried it.
It's a real shame - as it's so close to being good.
MS Fakes with the option I used for this. As John notes you need VS.Net Premium or higher unfortunately. I wrote up some notes on doing this here:
Andy
Andy, thanks for the info! I will look into MS Fakes. No luck with mocks from Moq so far. I was able to mock IPublishedContent but you can't mock extension methods, so GetPropertyValue was giving me a hard time.
Hey,
Instead of using GetPropertyValue
In your Unit Test:
Hope this will help :)
is working on a reply...