By non-contractual parameters, I mean parameters that are not interfaces or service dependencies, something like class Person(string name)
.
I am writing a webpage scraping application, and so far I've written it in the wrong order (hence the creation of this question). I made a class to parse HTML documents (from string format) and give me all the urls and images in it.
That class has the following description:
public class PageParser
{
private readonly string _html;
public PageParser(string html) {
_html = html;
}
public IEnumerable<string> GetImages() {
/* not important */
}
public IEnumerable<string> GetLinks() {
/* not important */
}
}
This code works great, unit-tested, 100% coverage, etc... The problem is now how do I write unit-tests for code that uses this class without worry about the constructor of this class. I only need this new class to work with the behavior of the PageParser
.
The pseudo code for this new functionality is as follows:
public Report CreateReport(string url)
{
var html = _webClient.DownloadString(url);
var parser = new PageParser(html);
var images = parser.GetImages();
var links = parser.GetLinks();
var relevantLinks = links.Where(l => l.Contains('something'));
return _reportBuilder.Create(images, relevantLinks);
}
The problem that I have is I don't want to have a bunch of unit-tests that have epically sized HTML documents for all my various test cases the CreateReport
method can have.
The options I have come up with are:
1) Leave everything as is
Leave the class structure as is, just live with having tests with large setup variables
2) Expose the page parser (+interface) from a Factory
Create an interface for PageParser
, and create a factory with corresponding interface.
interface IPageParserFactory
{
IPageParser Create(string html);
}
class PageParserFactory : IPageParserFactory
{
IPageParser Create(string html)
{
return new PageParser(html);
}
}
Then the resulting pseudo code would look something as follows.
// ... download string
var pageParser = _pageParserFactory.Create(html);
// ... create report
3) Move the parameter html to each method and create an interface (so now the class has no construction dependencies)
interface IPageParser
{
IEnumerable<string> GetImages(string html);
IEnumerable<string> GetLinks(string html);
}
4) Something else entirely
If there's another pattern that solves this problem I would like to know it.