Knightics
Knightics

Reputation: 3

Unit test and moq work shows exception as: The following setups were not matched:

I'm working with moq but fails for verifyAll method call. I have no idea what I did wrong.

Class to be tested:

namespace ConsoleApplication2
{
    public class SomeUtil
    {
        public static List<Person> underAgePerson = new List<Person>();

        public static List<Person> females = new List<Person>();

        public static List<Person> males = new List<Person>();

        public static List<Person> deletePersons = new List<Person>();

        public SomeAdapter adapter;

        public SomeUtil()
        {
            this.adapter = new SomeAdapter();
        }

        public void Valid(List<Person> persons)
        {
            foreach (Person p in persons)
            {
                if (p.Name == null)
                {
                    deletePersons.Add(p);
                }

                if (p.Age < 18)
                {
                    if (!deletePersons.Contains(p))
                    {
                        deletePersons.Add(p);
                    }
                    underAgePerson.Add(p);
                }
                adapter.SetGender(p);
                if (p.Gender.Equals("Male", StringComparison.InvariantCultureIgnoreCase))
                {
                    males.Add(p);
                }

                else if (p.Gender.Equals("Female", StringComparison.InvariantCultureIgnoreCase))
                {
                    females.Add(p);
                }
            }

            foreach (Person p in deletePersons)
            {
                persons.Remove(p);
            }
            deletePersons.Clear();
        }
    }
}

SomeUtil class:

namespace ConsoleApplication2
{
    public class SomeAdapter
    {
        public virtual Person SetGender(Person p)
        {
            if (string.IsNullOrEmpty(p.Gender))
            {
                p.Gender = "Male";
            }
            return p;
        }
    }
}

Unit test:

[TestClass]
public class SomeUtilTest
{
    Mock<SomeAdapter> adapter;
    List<Person> persons;
    SomeUtil util;
    [TestInitialize]
    public void Initialize()
    {
        adapter = new Mock<SomeAdapter>();
        persons = new List<Person>();
        util = new SomeUtil();
    }

    [TestCleanup]
    public void CleanUp()
    {
        adapter.VerifyAll();
    }

    [TestMethod]
    public void Valid_WithEmptyName_ShouldRemove()
    {
        Person person = new Person();
        person.Gender = "";
        person.Age = 1;
        persons.Add(person);

        Person result = new Person();
        result.Age = 19;
        result.Gender = "Female";
        result.Name = "Dannie";

        adapter.Setup(a => a.SetGender(person)).Returns(result);
        int count = persons.Count;
        util.Valid(persons);

        Assert.AreEqual(count - 1, persons.Count);

    }
}

Upvotes: 0

Views: 1116

Answers (2)

Owen
Owen

Reputation: 7098

    public SomeUtil()
    {
        this.adapter = new SomeAdapter();
    }

Because you have new'd up the SomeAdapter and not injected into the SomeUtil class, so the mock that you are verifying is not the instance thats been interacted with in the code, it's a completely different object.

You need to inject the SomeAdapter dependency somehow, either by constructor or property injection. You can do this manually i.e.

In SomeUtil.cs

    public SomeUtil(SomeAdaptor adaptor)
    {
        this.adapter = adaptor;
    }

In Test setup:

    [TestInitialize]
    public void Initialize()
    {
        adapter = new Mock<SomeAdapter>();
        persons = new List<Person>();
        util = new SomeUtil(adapter.Object);
    }

Ideally however, you wouldn't be mocking and injecting a solid class but an interface or abstract type. Also, in your application (not test) you would likely want to use a DI framework like Ninject, or Windsor (Been a while since I did .NET so there might be different options now).

Chris

Upvotes: 2

Warren Rumak
Warren Rumak

Reputation: 3874

It's because your SomeUtil class is using the real SomeAdapter class, not the Mock class. Moq can't observe the usage of methods in a real class.

What you need to do is inject the instance of SomeAdapter into your SomeUtil class. Instead of:

    public SomeAdapter adapter;
    public SomeUtil()
    {
        this.adapter = new SomeAdapter();
    }

do this:

    public SomeAdapter adapter;
    public SomeUtil(SomeAdapter adapter)
    {
        this.adapter = adapter;
    }

then, in the unit test:

    [TestInitialize]
    public void Initialize()
    {
        adapter = new Mock<SomeAdapter>();
        persons = new List<Person>();
        util = new SomeUtil(adapter.Object);
    }

Note the use of adapter.Object. This gives you an instance of the class that is observed by Moq.

If you make those changes, your unit test will pass. But there is a deeper underlying principle here of dependency inversion which I encourage you to look into. Amongst many things, it makes using mock testing libraries much easier to work with.

Upvotes: 2

Related Questions