Álvaro García
Álvaro García

Reputation: 19356

how to mock an object that is used inside the tested method?

I am doing some tests to learn about how to mock methods that use dialog boxes. I have this classes:

My Interface, that is a wrapper for the MessageBox.

public interface IDialogoDummy
    {
        ResultadoDialogo dummy(string paramMensaje, string paramCaption, System.Windows.MessageBoxButton paramBotones, MessageBoxResult paramBotonPorDefecto);
    }

The class that implements my interface:

public class DialogoDummy : IDialogoDummy
    {
        //El método tiene que ser virtual para que moq pueda utilizarlo
        public virtual ResultadoDialogo dummy(string paramMensaje, string paramCaption, System.Windows.MessageBoxButton paramBotones, MessageBoxResult paramBotonPorDefecto)
        {
            MessageBoxResult resultado = System.Windows.MessageBox
                    .Show(paramMensaje,
                    paramCaption,
                    paramBotones,
                    MessageBoxImage.None,
                    paramBotonPorDefecto);

            if(resultado == MessageBoxResult.Cancel)
            {
                return ResultadoDialogo.Cancel;
            }
            else if(resultado == MessageBoxResult.No)
            {
                return ResultadoDialogo.No;
            }
            else if(resultado == MessageBoxResult.None)
            {
                return ResultadoDialogo.None;
            }
            else if(resultado == MessageBoxResult.OK)
            {
                return ResultadoDialogo.OK;
            }
            else if(resultado == MessageBoxResult.Yes)
            {
                return ResultadoDialogo.Yes;
            }
            else
            {
                return ResultadoDialogo.Unknown;
            }
        }
    }

And a class that use my method:

public class DialogoDummyMethods
    {
        //El método tiene que ser virtual para que moq pueda utilizarlo
        public int getInt()
        {
            IDialogoDummy miGestor = new DialogoDummy();
            ResultadoDialogo resultado = miGestor.dummy("OK es 0 y cancel es 1", "Test", MessageBoxButton.OKCancel, MessageBoxResult.Cancel);
            int intResultado;
            if (resultado == ResultadoDialogo.OK)
            {
                intResultado = 0;
            }
            else
            {
                intResultado = 1;
            }

            return intResultado;
        }
    }

And this is my Test:

[TestMethod]
        public void DialogoTest01()
        {
            //La clase que se va a probar, que en este caso tiene también el método que se tiene que hacer mock, de modo.
            Mock<IDialogoDummy> miDialogoDummyMock = new Mock<IDialogoDummy>();
            //Se indica que  cuando se llame al método dummy, con cualquier cadena tanto de mensaje como de caption, y con botones OKCancel y valor por
            //defecto Canceal, devuelva 0.
            miDialogoDummyMock.Setup(x => x.dummy(It.IsAny<string>(), It.IsAny<string>(), System.Windows.MessageBoxButton.OKCancel, System.Windows.MessageBoxResult.Cancel))
                .Returns(GTS.CMMS.Client.Dialogos.ResultadoDialogo.OK);

            DialogoDummyMethods misMetodos = new DialogoDummyMethods();
            int intResultado = misMetodos.getInt();
            Assert.AreEqual(0, intResultado, "Debería ser 0");
        }

The problem is taht the mock object is different to the object that is created in the method that I want to test, so when the method to test is executed, the messageBox is shown and I have to select an option.

How can I test my getInt method without the needed to select an option in the dialog?

Thanks so much.

Upvotes: 1

Views: 99

Answers (1)

Sergey Berezovskiy
Sergey Berezovskiy

Reputation: 236208

Your SUT (class which you are testing) should depend on abstractions only. Don't instantiate dependencies inside class - that introduces dependency on concrete class, which you cannot mock. Inject dependencies via constructor/property/parameter dependency injection. That will allow you to provide mocked dependency implementation.

So, all together:

1) Depend on abstraction

public class DialogoDummyMethods
{
   private IDialogoDummy miGestor;

   public int getInt()
   {
        // DialogoDummyMethods knows nothing about IDialogoDummy implementation
        var resultado = miGestor.dummy(
             "OK es 0 y cancel es 1", "Test", 
             MessageBoxButton.OKCancel, MessageBoxResult.Cancel);

        return resultado == ResultadoDialogo.OK ? 0 : 1;
   }
}

2) Inject abstraction through constructor. Note - if only one method needs IDialogoDummy, then you can inject it as method parameter (in that case you don't need IDialogDummy as class field)

public DialogoDummyMethods(IDialogoDummy miGestor)
{
    this.miGestor = miGestor;
}

3) Mock dependency for unit-testing and inject mocked dependency to class which you are testing

var miDialogoDummyMock = new Mock<IDialogoDummy>();
// setup mock here
var misMetodos = new DialogoDummyMethods(miDialogoDummyMock.Object);
int intResultado = misMetodos.getInt();
Assert.AreEqual(0, intResultado, "Debería ser 0");

Upvotes: 1

Related Questions