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
0 votes
Tripping over a couple errors telling me methods are called more than once (which is not making any sense to me at all).

Utilities.ExMonitor.get_IsInitialized() has 1 more expected calls
UnitTest.FileSystemWatcher_wrap.set_EnableRaisingEvents() has 1 more expected calls

        [TestMethod()]
        public void StopTest()
        {
            Mock mockMonitor = MockManager.Mock(typeof(ExlMonitor), Constructor.Mocked);
            MockObject<FileSystemWatcher_wrap> mockWatcher = MockManager.MockObject(typeof(FileSystemWatcher_wrap)) as MockObject<FileSystemWatcher_wrap>;

            // create the object and also an accessor to private info
            ExMonitor ExMonObj = new ExMonitor();
            Util_ExMonitorAccessor privateMonitor = new Util_ExMonitorAccessor(ExMonObj);

            mockMonitor.ExpectGet("IsInitialized", true);

            mockWatcher.ExpectSet("EnableRaisingEvents");

            // call the method
            privateMonitor.Stop();
        }


    class ExMonitor 
    {
        private FileSystemWatcher _watcher;
        private bool _isInitialized = false;


        public ExMonitor()
        {
               o o o
        }

        public void Stop()
        {
            if (_isInitialized)
            {
                _watcher.EnableRaisingEvents = false;

                // wait a moment for events to settle
                // in case of race condition (event arrives at same time Stop)
                System.Threading.Thread.Sleep(50);
            }
        }
asked by cabin (2.3k points)

7 Answers

0 votes
Hi,

The error message is not about something being called more than once, but rather about these properties not being called at all. My guess is that it is not called because the field _isInitialized is not set to true. You are setting the IsInitialized property, but the field is not affected. Setting the field can be done using reflection, or the ObjectState class provided with Isolator.

Why are you using the old Reflective Mocks APIs? I would recommend using the new (actually, 2 years old now) AAA API to create tests - it's more easy to read and write tests this way. You can learn more about the AAA c# API at our online documentation (https://www.typemock.com/Docs/UserGuide/) under
Using Typemock Isolator -> C# API.

Thanks,
Doron
Typemock Support
answered by doron (17.2k points)
0 votes
Why not use AAA? Because TypeMock 4.2.x causes dozens of pre-existing tests to fail. So we're stuck with 4.1.
Although we do have a couple people working to resolve these problems, but that work is ongoing. (One issue I know of is that automatic field/property mocking introduced problems.)
answered by cabin (2.3k points)
0 votes
Cabin,

You are considering upgrading to a version we released 3 years ago, and in the meanwhile we're on version 6.0.3. I strongly recommend upgrading as there are tons of new features and bug fixes you are missing out on. If you need help ironing out breaking tests let me know and we'll work with you on that.

Doron
Typemock Support
answered by doron (17.2k points)
0 votes
No, we are not considering upgrading to 4.2. We have been working to upgrade to 5.4.

Backward compatibility has been broken since the 4.2 release (I don't have all the details). Because we have a large number of pre-existing tests and upgrade requires effort that costs $$, we were rather forced to ignore new versions for a while (a couple years, during which AAA was introduced). With the advent of Windows Vista & Windows 7, we've allocated resources to upgrade to a Typemock that is officially supported on Win 7 (I vaguely recall, they've been working with 5.4.4).
answered by cabin (2.3k points)
0 votes
Hi Cabin,

I see a problem in the usage of mockWatcher.
In order to fake its behavior you are using MockManager.MockObject
This is good if you are sending the faked object to the method under test.

It seems that what you want to do here is use MockManager.Mock which will fake the next time new is called on FileSystemWatcher_wrap

Please let me know if it helps.
answered by ohad (35.4k points)
0 votes
1)
Somewhere in TypeMock documentation, I thought I had read it was possible to mock fields. However, I was having trouble mocking "_IsInitialized". For this reason, I added property "IsInitialized", only so I could mock it. Then I neglected to change my unit test. Doron pointed out this problem. Thanks.
Should I be able to mock private data fields?

In the end, decided that mocking this one line wasn't strictly necessary. Instead, I force the value to true and the remainder of the test will reveal if it enters the conditional statement. (see updated test code below)

2)
A colleague suggested that I use mockMonitor.Object, instead of new ExMonitor. This seems to be working, but I don't really understand the difference. Can you enlighten me? Compare the original to the modified version below.

3)
The same colleage also suggested that I can mock FileSystemWatcher without need for a wrapper. To my surprise, this seems successful (see code below). But checking my TypeMock version on this particular computer, I see it is 5.4 (not standard for our organization). Is it correct that this will fail using 4.1 ?

  [TestMethod()]
  public void StopTest()
  {
      MockObject<ExMonitor> mockMonitor = MockManager.MockObject(typeof(ExMonitor), Constructor.Mocked) as MockObject<ExMonitor>;
      ExMonitor ExMonObj = mockMonitor.Object;
      Util_ExMonitorAccessor privateMonitor = new Util_ExMonitorAccessor(ExMonObj);
      privateMonitor._isInitialized = true;

      MockObject<FileSystemWatcher> mockWatcher = MockManager.MockObject(typeof(FileSystemWatcher)) as MockObject<FileSystemWatcher>;       
      privateMonitor._watcher = mockWatcher.Object;

      mockWatcher.ExpectSet("EnableRaisingEvents").Args(false);

      // call the method
      ExMonObj.Stop();
  }
answered by cabin (2.3k points)
0 votes
Hi Cabin,

1. Yes you can change the value of fields with the Isolator.
you can use class ObjectState in order to that.
You can see the usage of ObjectState in the online documentation here

2. About the mockMonitor.Object:
When you write this line:
MockObject<ExMonitor> mockMonitor = MockManager.MockObject(typeof(ExMonitor), Constructor.Mocked) as MockObject<ExMonitor>;

mockMonitor is the mock controller, that means you can use the various MockObject API calls to set the mocked instance behavior. However if you have a method that expects ExMonitor as an argument you need to pass an instance of ExMonitor to the method. MockObject lets you do that with its property MockObject.Object.
Another important issue to understand is the difference between MockManager.Mock and MockManager.MockObject:
Using MockManager.Mock will mock the next time 'new' is called on the mocked type. Using MockManager.MockObject creates a mocked instance on the spot and you can retrieve with the MockObject.Object property.

3. Isolator has limitation faking types that are on mcorlib.dll. However FileSystemWatcher class is in System.dll so you can fake it.
answered by ohad (35.4k points)
...