Unit testing with Umbraco 13 error
# help-with-umbraco
t
Hi I'm trying to unit test some sections of Umbraco. I need to create some mock content to pass to my test method. I've set it up with xUnit and MOQ. I'm setting up a test product for example and I get into a method where I get an error. The error received is System.TypeInitializationException: 'The type initializer for 'Umbraco. Extensions. FriendlyPublishedContentExtensions' threw an exception ArgumentNullException: Value cannot be null. Arg_ParamName_Name The Product is an Umbraco document type, with a page and custom properties. When I set up the mock object, I do something like var pi = new Mock(); pi.Setup(p=> p.Id).Returns(1111); // if does NOT exist I've searched on this and it seems it's doable however I don't understand what I'm missing as everything I read seems it was tailored for their scenario but I can't figure out what criteria I need to meet to overcome this. I'm passing in my mock object of Product in this case when declaring a new product and passing in publishedfallbackvalue too i.e. var p = new product(pi.object, _publishedFb.object) But when my method receives this I get the above error and I believe in missing setting some property somewhere, somehow. Appreciate any help you could provide
j
hi @TigerMan i'm hitting the exact same problems mocking
IPublishedContent
, mainly getting into a 'you can't mock extension methods' nightmare... did you get any further with this? i'm coming to the conclusion that the only way to unit test anything with
IPublishedContent
is to write a wrapper service for all the extension methods...
t
@jake williamson hi unfortunately no. There we're extension methods I used to mock some properties but I didn't get very far with it. Sorry
d
What I have done is I've written wrapper types in my code that call these extensions. That way, I can mock my own wrapper type instead of umbraco's built-in stuff. It's a little extra overhead, but makes testing a lot easier at least
j
hey there, thank you for the reply 😉 yup, that's been our approach from v8 onwards and in fact the only approach when it comes to extension methods. as
Url
used to be a property, it's not been a problem in the past but now it's an extension method, it's begun being an issue... it's a pain, as you need to write a wrapper for every extension methods class and maintain them - but i guess it's a 'do once and make a nuget package' kinda thing. the bit i go in loops with though is that the umbraco docos state: https://docs.umbraco.com/umbraco-cms/reference/common-pitfalls#usage-of-singletons-and-statics
Copy code
Generally speaking, if you are writing software these days you should be using Dependency Injection principles. If you do this, you probably aren't using Singletons or Statics (and for the most part you shouldn't be!).
seems weird that the docos say 'avoid statics' but then the core has them?!
d
Yeah, I get what you're saying. I can't speak for HQ, but I remember reading that this was a deliberate choice to keep a more consistent API. That is: it allows everybody to keep working the way they've always done. They also use a static service provider commonly in constructors to avoid breaking changes, but they always mark those as obsolete and remove them in future major versions.
i
Hey all, any update or new findings for the problem? We are also a bit stuck with mocking the extension methods. How did you solve it with wrappers?
d
Say you have a service like this:
Copy code
csharp
public class MyService
{
    public Card ConvertToCard(IPublishedContent content)
    {
        return new Card(content.Url(), content.Name);
    }
}
This class is not testable, because it uses the
.Url()
extension. So what I do, is I create a wrapper type:
Copy code
csharp
public interface IUrlReader
{
    string GetUrl(IPublishedContent content);
}

public class UrlReader : IUrlReader
{
    public string GetUrl(IPublishedContent content)
        => content.Url();
}
And then I modify my service like this:
Copy code
csharp
public class MyService(IUrlReader urlReader)
{
    public Card ConvertToCard(IPublishedContent content)
    {
        return new Card(urlReader.GetUrl(content), content.Name);
    }
}
Now I can mock/fake the
IUrlReader
interface and run unit tests on this code.
8 Views