2

Problem:

I'm having trouble mocking two properties of my Form using the Moq framework. There are examples of how to do what I'm trying to do out there, but they are all with properties whose type is simple, like string or int.

The Fields property of IMainForm are not being initialized like they do for MainForm, which makes sense to me why (interfaces do not allow this type of initialize to happen). I just don't know how to overcome it.

I have a form defined something like this:

public partial class MainForm : XtraForm, IMainForm
{
    ...

    #region Public Properties

    public RichEditDocumentServer DocServer { get; } = new RichEditDocumentServer();

    public Dictionary<string, string> Fields { get; } = new Dictionary<string, string>();

    #endregion

    ...
}

In my tests, my fixture's setup is as follows:

...
#region Private Variables

private Mock<IConnector> _arc = new Mock<IConnector>();
private Mock<IMainForm> _arForm = new Mock<IMainForm>();
private MainController _controller;

#endregion

[TestFixtureSetUp]
public void FixtureSetup()
{
    _arc.SetupAllProperties();
    _arForm.SetupAllProperties();
    _controller = new MainController(_arc.Object)
    {
        View = _arForm.Object
    };
}
...

The line that fails in my test (but passes when I run with a UI):

View.Fields.Add(...) // throws NullReferenceException because Fields in null

Intention:

I don't want the public interface to my forms allowing the Fields or DocServer properties to be set to something other than what they are initially set to. But this still allows .Add(...) to be called on the Fields property for instance. I intend to test that adding KeyValuePairs to the Fields is a successful step in making more business-logic-y type stuff to happen.

Question:

What is the Moq way of initializing complex properties with no setter? My tests fail because these properties are null. Thank you.

Jake Smith
  • 2,332
  • 1
  • 30
  • 68
  • 1
    why don't you simply use `SetupGet`? – Old Fox Sep 08 '15 at 07:50
  • 2
    I agree with @OldFox. You can just do something like `_arForm.Setup(x => x.Fields).Returns(yourTestDictionary);`. Or if you do not care to keep a reference to the dictionary in your test, just `_arForm.Setup(x => x.Fields).Returns(new Dictionary());`. – Jeppe Stig Nielsen Sep 08 '15 at 08:49
  • I was afraid of `...).Returns(new Dictionary());` not persisting any items that are added to the `Dictionary` using the `.Add(...)` method during the run of the test. Wouldn't returning a new dictionary like in your last suggestion give me a new dictionary EACH time I call the getter (losing what has been added to it thus far)? – Jake Smith Sep 08 '15 at 17:15
  • @JakeSmith `.Returns(new Dictionary());` won't persist the items... you need the first option: `_arForm.Setup(x => x.Fields).Returns(yourTestDictionary);` read my answer... – Old Fox Sep 08 '15 at 22:06
  • @OldFox That is wrong. `.Returns(new Dictionary())` **will** persist. A new `Dictionary<,>` will be created **before** `Returns` is called. Moq will hold on to a reference to that single instance of `Dictionary<,>`. Since that is a mutable type, the instance will change when people `Add` to it etc. Maybe you were confusing it with the overload of `Returns` which takes in a `Func<>` as a kind of factory? I am talking about `.Returns(() => new Dictionary())` which will lead to a new (and empty) dictionary being created for each invokation of the property `get`. – Jeppe Stig Nielsen Sep 11 '15 at 07:32
  • @JeppeStigNielsen you are right, I got confused with the `Func`, however in my answer I didn't want it to return a new instance... – Old Fox Sep 11 '15 at 09:03

1 Answers1

5

You have to use SetupGet method; this method exist to handle the cases where you want to mock the getter method.(Well you can use regular Setup instead of SetupGet...)

As @Jeppe Stig Nielsen comment you can set the method to return a new instance each time it calls or to return the same instance. In your case you are looking for option B:

    private Mock<IConnector> _arc;
    private Mock<IMainForm> _arForm;
    private MainController _controller;
    private Dictionary<string, string> _fields;

    [TestFixtureSetUp]
    public void FixtureSetup()
    {
        _fields = new Dictionary<string, string>();
        _arc = new Mock<IConnector>();
        _arForm = new Mock<IMainForm>();

        //The magic line:
        _arForm.SetupGet(x => x.Fields).Returns(_fields);

        _controller = new MainController(_arc.Object)
        {
            View = _arForm.Object
        };
    }

The above code snippet won't throw the exception and provide you an access to the added items...

Old Fox
  • 8,629
  • 4
  • 34
  • 52
  • 1
    If you want a new dictionary each time, be sure to use an overload of `.Returns` which takes in a `Func` argument called `valueFunction`, for example `.Returns(() => new Dictionary())`. – Jeppe Stig Nielsen Sep 11 '15 at 07:36
  • @JeppeStigNielsen read again my answer.... I didn't want to return a new `Dictionary` each time.... – Old Fox Sep 11 '15 at 08:58
  • 1
    I agree, your answer was entirely correct. My comment was not meant as a correction, it was more like some extra info (which was not even relevant in the asker's use case, I admit) on how to do "option A". – Jeppe Stig Nielsen Sep 11 '15 at 11:01
  • @JeppeStigNielsen ha, my fault, thanks for extending my answer :) – Old Fox Sep 11 '15 at 11:06
  • I was really hoping that `Moq` supported this in a way outside of having to persist the property's value manually. But this does work...thank you. – Jake Smith Sep 11 '15 at 16:22