Question

I have a Project entity that has a set of Word entities within. My WordsRepository depends on the Project entity. It should operate over the set of words that the project includes.

public interface IWordsRepository
{
    List<Word> FetchAll();
}
public class WordsRepository : IWordsRepository
{
    private readonly Project _project;

    public WordsRepository(Project project)
    {
        if (project == null)
            throw new ArgumentNullException("project");
        this._project = project;
    }
    public List<Word> FetchAll()
    {
        // code for retrieveing words for the project from the database
    }        
}

Now let's dig a little deeper. Here is my ProjectsModel.

public class ProjectsModel
{
    private readonly IProjectsRepository _rep;
    private IWordsRepository _wordsRep;
    private IProjectsModelObserver _presenter;

    // Regular contructor for usual purpose
    public ProjectsModel()
    {            
        this._rep = new ProjectsRepository(Program.context);
    }

    public ProjectsModel(IProjectsRepository repository)
    {
        this._rep = repository;
    }

    public virtual void AttachPresenter(IProjectsModelObserver observer)
    {
        this._presenter = observer;
    }

    public List<Project> projects
    {
        get
        {
            List<Project> tmpList = _rep.FetchAll();
            return (tmpList != null) ? tmpList : new List<Project>();
        }
    }

    private Project _selectedProject;
    public Project selectedProject
    {
        get
        {
            if (_selectedProject == null)
                _selectedProject = projects.FirstOrDefault();
            return _selectedProject;
        }
        set
        {
            if (!projects.Contains(value))
                throw new InvalidOperationException("Project not in the Projects list");

            _selectedProject = projects[projects.IndexOf(value)];
            // Recreating Words repository depending on project
            // Here is my issue:
            // As I should recreate the Words repository here, passing a new selected project 
            // how can I mock it and make this class testable?
            this._wordsRep = new WordsRepository(this._selectedProject);

            if (this._presenter != null)
                this._presenter.SelectedProjectChanged(_selectedProject);
        }
    }

    private List<Word> _words;
    public List<Word> Words
    {
        get
        {
          // Fetching set of words in Project. Just invoking a words repository
        }
    }
}

When the model's selected project is changed, it should recreate the WordsRepository, but it isn't testable this way.

How can I mock it?

Was it helpful?

Solution

You need to use a factory to create the new WordsRepository. As you probably know, whenever you see the word new in your code, it's probably a good idea to make a Factory class that will give you that instance being requested, because then you can mock the factory to return whatever instance you want at testing time.

So you would change to this:

  _WordsRep = WordsRepositoryFactory.CreateNewRepository(_selectedProject);

OTHER TIPS

Look into Managed Extensibility Framework. Basically, you have a single interface with multiple implementations on that interface. But, at runtime you want to be able to switch out these implementations for one another. In order to do so, you cannot statically link against either of the implementations, and should allow a framework to determine which one to use for you.

MEF will allow you to [Import(typeof(IWordsRepository))]. This will allow you to drop in a different implementation as a deployment item. The code will look something like this.

[Export(typeof(IWordsRepository))]
public class WordsRepository : IWordsRepository
{
   public List<Word> FetchAll()
   {
       //this class will hit the database
   }
}



[Export(typeof(IWordsRepository))]
public class WordsRepositoryTest : IWordsRepository
{
   public List<Word> FetchAll()
   {
        //this class will not go to the database, maybe an xml file or something.    
   } 
}

Then, your ProjectsModel will use:

[Import(typeof(IWordsRepository))]
IWordsRepository _repo;

Store these two types in two different dlls, and drop the test type in as a deployment item for your unit tests. It will use whichever implementation you drop in.

More on MEF: http://msdn.microsoft.com/en-us/library/dd460648.aspx

More on deployment items: http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.deploymentitemattribute(v=vs.80).aspx

I'm finding your code hard to understand, but a factory is an option, as Tejs mentions. Another possibility could be to not have a setter, but a SetSelectedProject(IWordsRepository) method. This may or may not be a possibility in your specific project.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top