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
Hi,

I want to test this (UI) code from a login dialog:
        private void btnOk_Click(object sender, RoutedEventArgs e)
        {
            bool isValid = checkPassword(txtUsername.Text, txtDomain.Text, pwbPassword.Password);

            if (isValid)
            {
                this.DialogResult = true;
            }
            else
            {
                string msg = "The combination of username, password and domain is not valid, or your account is locked.";
                string caption = "Login failed";
                MessageBox.Show(msg, caption, MessageBoxButton.OK, MessageBoxImage.Stop);
            }

        }


The checkPassword() will be tested with an own test.

I started with this test code:
            // Arrange
            LoginWindow_Accessor target = new LoginWindow_Accessor();
            object sender = null;
            RoutedEventArgs e = null;

            Isolate.Fake.StaticMethods<System>(Members.ReturnRecursiveFakes);
                        
            // Act
            target.btnOk_Click(sender, e);

            // Assert
            Isolate.Verify.WasCalledWithAnyArguments(
                () => System.Windows.MessageBox.Show(
                    string.Empty, 
                    string.Empty, 
                    MessageBoxButton.OK, 
                    MessageBoxImage.Stop)
                    );

The text boxes in the form are empty, so checkPassword will return false and the messagebox will be called. The test is ok.

Now I want do fake the checkPassword function and first return 'false' again by adding this code (on top):
            LoginWindow_Accessor fake = Isolate.Fake.Instance<LoginWindow_Accessor>();
            Isolate.NonPublic.WhenCalled(fake, "checkPassword").WillReturn(false);
            Isolate.Swap.NextInstance<LoginWindow_Accessor>().With(fake);

But than the test fails: "TypeMock Verification: Method System.Windows.MessageBox.Show(String, String, MessageBoxButton, MessageBoxImage) was expected but was not called"

What's wrong here?

Thanks,

Mike
asked by mike (680 points)

5 Answers

0 votes
Hi Mike,

I'd recommend you to use the actual class instead of using the accessor wrapper.

In the test you can instantiate the LoginWindow class as the class under test. The act statement sould change into:
Isolate.Invoke.Method(target, "btnOk_Click", sender, e);


In general, Isolator provides a lot of the functionality that the accessors provide through Isolate.NonPublic APIs and through ObjectState.

Please let us know if it works.

Regards,
Elisha,
Typemock Support
answered by Elisha (12k points)
0 votes
Hi Elisha,

if I try this test code now:
            // Arrange
            LoginWindow fake = Isolate.Fake.Instance<LoginWindow>();
            Isolate.NonPublic.WhenCalled(fake, "checkPassword").WillReturn(false);
            Isolate.Swap.NextInstance<LoginWindow>().With(fake);

            // Arrange
            LoginWindow target = new LoginWindow();
            object sender = new object();
            RoutedEventArgs e = new RoutedEventArgs();

            Isolate.Fake.StaticMethods<System>(Members.ReturnRecursiveFakes);
                        
            // Act
            Isolate.Invoke.Method(target, "btnOk_Click", sender, e);
            
            // Assert
            Isolate.Verify.WasCalledWithAnyArguments(
                () => System.Windows.MessageBox.Show(
                    string.Empty,
                    string.Empty,
                    MessageBoxButton.OK,
                    MessageBoxImage.Stop)
                    );

... the assert (Isolate.Verify) throws a not called exception.

If point the cursor between the braces:
RoutedEventArgs e = new RoutedEventArgs();

your "helper" appears with "Fake RoutedEvent Alt+7". If I press Alt+7 the text "fakeRoutedEvent" will be inserted. Now the helper says "Set Object Behavior Alt+7". If I press Alt+7 again, Visual Studio (2010) crashes every time ... :cry:

What can I do? How should I instance sender and e?

Ciao,
Mike
answered by mike (680 points)
0 votes
Hi Mike,

I've edited the test a little. The test will check that if checkPassword() returns false the message box is shown:

LoginWindow target = new LoginWindow();
Isolate.NonPublic.WhenCalled(target, "checkPassword").WillReturn(false);
Isolate.Fake.StaticMethods<MessageBox>(Members.ReturnRecursiveFakes);

object sender = new object();
RoutedEventArgs e = Isolate.Fake.Instance<RoutedEventArgs>();
Isolate.Invoke.Method(target, "btnOk_Click", sender, e);
            
Isolate.Verify.WasCalledWithAnyArguments(
    () => System.Windows.MessageBox.Show(
        string.Empty,
        string.Empty,
        System.Windows.MessageBoxButton.OK,
        System.Windows.MessageBoxImage.Stop));


As can be seen in the test, the RoutedEventArgs can be created as a fake instance without accessing it's constructor directly.

Please let me know if it helps.

Regards,
Elisha,
Typemock Support
answered by Elisha (12k points)
0 votes
Hi Elisha,

that works! Now, my two tests look like:
        public void btnOk_ClickTest_passwordOk()
        {
            // Arrange
            LoginWindow target = new LoginWindow();

            Isolate.NonPublic.WhenCalled(target, "checkPassword").WillReturn(true);
            Isolate.WhenCalled(() => {target.DialogResult = true;}).IgnoreCall();

            object sender = new object();
            RoutedEventArgs e = Isolate.Fake.Instance<RoutedEventArgs>();
                        
            // Act
            Isolate.Invoke.Method(target, "btnOk_Click", sender, e);
            
            // Assert
            Isolate.Verify.WasCalledWithArguments(
                () => { target.DialogResult = true; }).Matching(args => (bool)args[0] == true);
        }

(Is the assert OK? It works, but writing "target.DialogResult = true;" and checking for true feels a little bit strange ... :wink: )

        public void btnOk_ClickTest_passwordFailed()
        {
            // Arrange
            LoginWindow target = new LoginWindow();
            Isolate.NonPublic.WhenCalled(target, "checkPassword").WillReturn(false);
            Isolate.Fake.StaticMethods<System>(Members.ReturnRecursiveFakes);

            object sender = new object();
            RoutedEventArgs e = Isolate.Fake.Instance<RoutedEventArgs>();

            // Act
            Isolate.Invoke.Method(target, "btnOk_Click", sender, e);

            // Assert
            Isolate.Verify.WasCalledWithAnyArguments(
                () => System.Windows.MessageBox.Show(
                    string.Empty,
                    string.Empty,
                    MessageBoxButton.OK,
                    MessageBoxImage.Stop)
                    );
        }



Now "my colleague" changes the production code into ...
            if (isValid)
            {
                MessageBox.Show("Bingo");
                this.DialogResult = true;
            }

... and I want to make shure that the test fails now. I want to make shure, that any message window will fail. I can add something like that:
            Isolate.Verify.WasNotCalled(
                () => System.Windows.MessageBox.Show(
                    string.Empty)
                    );

But if my colleague adds a caption, the verify will not work. So, I don't know how many parameters the Messagebox.Show will have. How can I make shure, that I catch all of them?

Thanks,

Mike
answered by mike (680 points)
0 votes
Mike,

First, regarding the assert - I would use another API:
Isolate.Verify.WasCalledWithExactArguments(() => { target.DialogResult = true; });

This would verify the arguments against what you passed in, meaning checks true was set.

Regarding the second question, this is a good point - I will add a feature suggestion to provide an option that the WasCalledWithAny API will not be overload specific. To make the test more robust you can use the non public API that's string based but does not rely on arguments:
Isolate.Verify.NonPublic.WasCalled(typeof(MessageBox), "Show");


Hope this helps.
Doron
Typemock Support
answered by doron (17.2k points)
...