chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
Welcome to Typemock Community! Here you can ask and receive answers from other community members. If you liked or disliked an answer or thread: react with an up- or downvote.
0 votes
Hello,

I am probably overlooking something simple, but I don't seem to achieve an obvious thing. I have a class with a public constructor that initialized several fields, i.e.

public class MyClass
{
private string m_A;
private string m_B;

public MyClass(string a, string b)
{
m_A = a;
m_B = b;
}

...
}

I need to mock just the constructor call, leaving the rest of the method unmocked. How should I do this? I tried the following:

MockManager.Init();
using(RecordExpectations recorder = new RecordExpectations())
{
MockManager.Mock(typeof(MyClass), Constructor.NotMocked);
MyClass mc = new MyClass("a", "b");
...
}
...
MockManager.Verify();

But when I check the instance of mc after calling a constructor, I see that all fields are null! I am also not sure if calling Mock(typeof) is correct, 'cause I only need to mock a constuctor call, not subsequent method calls.

Can you help me please?
Thanks in advance
Vagif Abilov
Oslo Norway
asked by vagif (19.4k points)

9 Answers

0 votes
If you're using Natural mocks (the "using RecordExpectations" block) you probably don't want Reflective mocks (the "MockManager" calls) inside there. It just gets confusing.

If you mock the constructor, then it's not going to call anything inside the constructor, so the fields will remain uninitialized (which is why they're null). If you want the constructor to run, don't create the object inside the mock recording block. Instead, only mock the things you really need mocked.

Here is some example code, using your sample class and a method I added ("ConcatValues") so we can get values out and have something to mock.

You should be able to see various effects when you see what's in the mocking blocks and what's not, where things get constructed and such, and remember that all of the unit tests here pass.

public class MyClass
{
  private string m_A;
  private string m_B;

  public MyClass(string a, string b)
  {
    m_A = a;
    m_B = b;
  }

  public string ConcatValues()
  {
    if (m_A == null && m_B == null)
    {
      return null;
    }
    return m_A + m_B;
  }
}

[TestFixture]
[VerifyMocks]
public class MyClassTest
{
  [Test]
  public void MockConstructor()
  {
    using (RecordExpectations recorder = RecorderManager.StartRecording())
    {
      // The arguments here are ignored so it
      // doesn't matter what you put. Generally
      // I put null for all args I don't care about
      // but for illustration, I'll use real values.
      MyClass dummy = new MyClass("foo", "bar");
    }
    MyClass real = new MyClass("x", "y");
    Assert.IsNull(real.ConcatValues());
  }

  [Test]
  public void MockMethodReturnOnce()
  {
    MyClass real = new MyClass("x", "y");
    using (RecordExpectations recorder = RecorderManager.StartRecording())
    {
      // Mock ONE call to the ConcatValues method
      string dummy = real.ConcatValues();
      recorder.Return("mocked!");
    }

    // The first call outside the block is mocked
    Assert.AreEqual("mocked!", real.ConcatValues());

    // The second call outside the block is NOT
    // because we only set up one mock.
    Assert.AreEqual("xy", real.ConcatValues());
  }

  [Test]
  public void MockMethodReturnAlways()
  {
    MyClass real = new MyClass("x", "y");
    using (RecordExpectations recorder = RecorderManager.StartRecording())
    {
      // Mock EVERY call to the ConcatValues method
      string dummy = real.ConcatValues();
      recorder.Return("mocked!");
      recorder.RepeatAlways();
    }

    // Every call outside the block is mocked for that instance...
    Assert.AreEqual("mocked!", real.ConcatValues());
    Assert.AreEqual("mocked!", real.ConcatValues());

    // This is a different instance, so it's not mocked.
    MyClass another = new MyClass("a", "b");
    Assert.AreEqual("ab", another.ConcatValues());

    // But the original is still mocked, regardless.
    Assert.AreEqual("mocked!", real.ConcatValues());
    Assert.AreEqual("mocked!", real.ConcatValues());
  }
}
answered by tillig (6.7k points)
0 votes
Thanks a log for your reply! However this is not exactly what I am trying to achieve. I want an attempt in the test to call a constructor of MyClass result in calling a constructor with different arguments.

For example, if I have the following line:

MyClass mc = new MyClass("c", "d");

I want a constructor to be called but with "a" and "b" instead:

MyClass mc = new MyClass("a", "b");

I.e. I am trying to intercept a call to a constructor, replace call parameters and initialize a MyClass object instance with different parameters. I agree it's not a real mocking of constructor since I am calling it, but I still want to change the way it's called.
answered by vagif (19.4k points)
0 votes
Ah, I see what you want to do...

.. but I don't know how to do that. Maybe the TypeMock folks can help out with that. I tried using the MockMethodCalled event and it didn't work for the constructor.

If it's new code you're writing, I might encourage you to redesign slightly for a better testability. I'm not a big fan of the "design for testability" thing, but you might be better able to do what you're doing with a private method you could mock. Like:

public class MyClass
{
  private string m_A;
  private string m_B;

  public MyClass(string a, string b)
  {
    m_A = a;
    m_B = b;
  }

  public string ConcatValues()
  {
    if (m_A == null && m_B == null)
    {
      return null;
    }
    return m_A + m_B;
  }
}

public class ConsumerClass
{
  private MyClass GetMyClassInstance()
  {
    return new MyClass("a", "b");
  }

  public string GetMyClassValue()
  {
    MyClass instance = this.GetMyClassInstance();
    return instance.ConcatValues();
  }
}

[TestFixture]
[VerifyMocks]
public class ConsumerClassTest
{
  [Test]
  public void ChangeCtorParams()
  {
    MyClass substitute = new MyClass("x", "y");
    Mock<ConsumerClass> mock = MockManager.Mock<ConsumerClass>();
    mock.ExpectAndReturn("GetMyClassInstance", substitute);
    ConsumerClass consumer = new ConsumerClass();
    Assert.AreEqual("xy", consumer.GetMyClassValue());
  }
}


Note how I'm mocking the private GetMyClassInstance "factory" method and instead returning a constructed instance with my desired state.

Generally, rather than mock the constructor parameters, I end up mocking the call to whatever public-facing method someone is interfacing with (like "ConcatValues"). That's what I did in the original examples.

Of course, you could fall back to good old fashioned reflection:
[Test]
public void ChangeCtorParams()
{
  MyClass instance = new MyClass("a", "b");
  typeof(MyClass).GetField("m_A", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(instance, "x");
  typeof(MyClass).GetField("m_B", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(instance, "y");
  Assert.AreEqual("xy", instance.ConcatValues());
}

But then you're really getting into brittle-test territory, where the test knows far too much about the inner workings of the class it's testing.
answered by tillig (6.7k points)
0 votes
Thanks again,

Well, I really hope to find more natural way of intercepting class constructor. TypeMock supports ExpectAndReturn that can be used to intercept a method call and replace its result with some other value. Basically I want to do the same but with a constructor: expect an object instantiation and replace a call "new MyClass(...)" with "new MyClass("a", "b")". Of course I can always redesign a class to support non-constructor-based object creation, but I feel it's wrong to redesign a class just for this purpose. Yes, classes should be designed with testability in mind, but usually designing for testability does not imply using some tricks that will only be used to enable some weird test.

So I still hope that there is a simpler way of intercepting constructor invocation. Perhaps somebody from TypeMock can elaborate.
answered by vagif (19.4k points)
0 votes
Hi,
There is a whole section about swapping arguments.

[Test,VerfiyMocks]
public void MockConstructor()
{
  using (RecordExpectations recorder = RecorderManager.StartRecording())
  {
    // The arguments here are swapped
    MyClass dummy = new MyClass("c", "d");
    recorder.CheckArguments(
      new Assign("a"), new Assign("b"));
  }
}
answered by eli (5.7k points)
0 votes
Well, holy smoke. You learn something new every day. Very cool!
answered by tillig (6.7k points)
0 votes
Thank you Eli, I will try the argument swapping as you suggested.

Vagif
answered by vagif (19.4k points)
0 votes
Hi,
There is a whole section about swapping arguments.

[Test,VerfiyMocks]
public void MockConstructor()
{
  using (RecordExpectations recorder = RecorderManager.StartRecording())
  {
    // The arguments here are swapped
    MyClass dummy = new MyClass("c", "d");
    recorder.CheckArguments(
      new Assign("a"), new Assign("b"));
  }
}


Eli, I ran some tests and I am not getting results that you suggested. I am posting now code samples in a new post.
answered by vagif (19.4k points)
0 votes
:idea: We have to tell Typemock to call the original method.

using (RecordExpectations recorder = new RecordExpectations())
{
   theClass = new MyClass("c", "d");
   recorder.CallOriginal.CheckArguments(new Assign("e"), new Assign("f"));
}
answered by eli (5.7k points)
...