Mocking Objects in YouTube API.

I wrote a class of service that works with the C # GData YouTube API. A typical use of the API includes requests for a YouTubeRequest object that calls the YouTube web service and deserializes the response in JSON format in the form of a Feed , Video or Playlist instance that contains data in the form of quite a few C # properties.

I want to unit test this class of service. In my code, the YouTubeRequest object is an external dependency, and it needs to be mocked, but it does not implement any interface, so I had to add an abstraction layer. This layer has methods that return these types of Video and Playlist , and I'm trying to use Moq to create a layout that creates, say, a dummy instance of Video with test data, but many properties on the Video class are read-only, and these Video , Playlist objects and Feed hard to build, often requiring instances of other types from the YouTube platform.

I'm new to unit testing, but from what I've seen in Rob Conery's videos, there are just some frameworks that are not module friendly, like ASP.NET Webforms.

What should I do in this situation? Am I incorrectly abstracting a YouTubeRequest object? I understand that this added layer of abstraction should be very simple, but if I added a call to, say, a map layer, I could map the data to my own types. Mocking an interface that returns my types would be a lot easier, since I could let you get and set properties and easily create dummy data. Although the code that interacts with YouTube is relatively small, I expect that over time it will increase in size and complexity, and therefore the idea of ​​abandoning unit testing is generally tedious.

+4
source share
4 answers

I have successfully generated fake dummy Video and Playlist objects and I am returning them back. Although certain properties of these types are read-only, I found another property called "AtomFeed", which is a get and set property. As it turned out, all read-only properties on Video and Playlist objects retrieve their data from the object provided through the AtomFeed property. I discovered this by reading the source code for the YouTube.NET client library . Ultimately, my problem arose due to my misuse of the YouTube library. As a result, this answer solves only my specific problem with the YouTube library, and not the general problems associated with mocking the interface, which should return complex, not settable properties.

+1
source

Generally, the best way to do something like this in C # is to have three different modules in your system: presentation, business, and data. In your case, the YouTube API is a data module. One way to write YouTube data services that makes testing easier is to simply call the API and translate the reponses (XML / JSON / etc) into POCOs (Plain-Old C # Objects). These POCOS are likely to be just classes with public properties that map exactly to the API schema:

 namespace YouTube { public class Video { public string Title { get; set; } public int Views { get; set; } // etc } } 

They should have little or no logic, and this is just an internal representation of the API. Now it allows you to easily create test data for the parts of your application that you really want to test: your business level. You can create more complex objects from POCOs, and you can easily do this in tests.

Then your presentation level will interact with your business level, and if you want, you can make fun of your business level to test the presentation level.

0
source

Turn it a little further.

As long as the YouTube MIGHT object already has these fields dependent on it, suppose it is not. Add an interface with something like IFeedSource and give it a method that says GetFeedForVideo (YouTubeVideo) . This way you get granular testability, very agnostic ( Param<YouTubeVideo>.Is.Anything ) and can easily return objects.

0
source

At any time when you cannot mock something because it does not have a constructor without parameters, a virtual method, an interface, or an abstract base class, you can always create a wrapper class to make it easier to ridicule.

Resharper makes this a lot easier by pressing Alt + Insert in the private member field and then selecting the "delegate members" option. Resharper will pretty much create a wrapper class for you by creating all public methods and properties and delegating the property / method to the selected selected variable. eg.

 private readonly Feed<T> _feed; 

Then you can create the appropriate constructor and mark all the tested methods / properties as virtual, for example

 public class GDataFeedWrapper<T> where T : Entry, new() { private readonly Feed<T> _feed; public GDataFeedWrapper(Feed<T> feed) { _feed = feed; } public virtual AtomFeed AtomFeed { get { return _feed.AtomFeed; } } public virtual bool AutoPaging { get { return _feed.AutoPaging; } set { _feed.AutoPaging = value; } } public virtual IEnumerable<T> Entries { get { return _feed.Entries; } } public virtual int Maximum { get { return _feed.Maximum; } set { _feed.Maximum = value; } } public virtual int PageSize { get { return _feed.PageSize; } } public virtual int StartIndex { get { return _feed.StartIndex; } } public virtual int TotalResults { get { return _feed.TotalResults; } } } 

Now that you need to return Feed, just return GDataFeedWrapper.

0
source

Source: https://habr.com/ru/post/1392123/


All Articles