Utilizando Moq estoy burlando de una propiedad, Report TheReport { get; set; } en una interfaz ISessionData para que yo pueda inspeccionar el valor que se establece en esta propiedad.

Para lograr esto, estoy usando SetupGet y SetupSet de la siguiente manera:

//class-level fields
protected Report _sessionReport;
protected Mock<ISessionData> SessionData { get; private set; }

Y en mi método de configuración de la…

SessionData = new Mock<ISessionData>();

SessionData
    .SetupSet(s => s.TheReport = It.IsAny<Report>())
    .Callback<RDLDesigner.Common.Report>(r =>
    {
        _sessionReport = r;
        SessionData.SetupGet(s => s.TheReport).Returns(_sessionReport);
    });

He encontrado este enfoque en StackOverflow y funciona, pero no entiendo por qué. Yo esperaba la llamada a SetupGet fuera de la SetupSet de devolución de llamada.

Puede alguien explicar cómo y por qué este enfoque funciona, y si es la más adecuada forma de burlarse de una propiedad de este tipo?

Editar

Utilizando SessionData.SetupProperty(s => s.TheReport); también funciona en mi escenario, pero todavía estoy interesado en cualquier explicaciones de cómo y por qué mi enfoque original trabajado.

2 Comentarios

  1. 32

    La razón por la devolución de llamada se utiliza en la llamada a SetupGet es que el _sessionReport de referencia se pasa por valor, esto significa que una posterior llamada al método Set no actualizar el valor devuelto por el método get.

    Para ver lo que está pasando con más claridad. Si tienes que configurar tu camiseta de la siguiente manera:-

    SessionData.SetupSet(s => s.Report = It.IsAny<Report>());
    SessionData.SetupGet(s => s.Report).Returns(_report);

    En pseudocódigo se Burlaban de la aplicación se verá un poco como

    public Report Report {
        set { }
        get { 
           //Copy of the value of the _report reference field in your test class
           return _reportCopy; 
        }  
    }

    Para hacer algo como esto no iba a funcionar:-

     ISessionData session = SessionData.Object
     Report report = new Report();
     session.Report = report;
     session.Report.ShouldEqual(report); //Fails
     _report.ShouldEqual(report); //Fails

    Obviamente tenemos que añadir algunos de comportamiento para el método de juego, así que nos pusimos hasta el Mock así

    SessionData.SetupSet(s => s.Report = It.IsAny<Report>())
               .Callback(s => _report = s);
    SessionData.SetupGet(s => s.Report).Returns(_report);

    Esto conduce a un objeto de burla de la implementación de mirar un poco como

    public Report Report {
        set {
           //Invokes delegate that sets the field on test class
        }
        get { 
           //Copy of the original value of the _report reference field
           //in your test class
           return _reportCopy; 
        }  
    }

    Sin embargo esto nos lleva al siguiente problema:-

      ISessionData session = SessionData.Object
      Report report = new Report();
      session.Report = report;
      _report.ShouldEqual(report); //Passes
      session.Report.ShouldEqual(report); //Fails!

    En esencia, el método «get» en la propiedad todavía devuelve una referencia al objeto original _report se apunta como la referencia fue aprobada por el valor de la SetupGet método.

    Por lo tanto, la necesidad de actualizar el valor del informe de captador devuelve cada vez que el setter se llama lo que conduce a su código original

    SessionData
       .SetupSet(s => s.TheReport = It.IsAny<Report>())
       .Callback<RDLDesigner.Common.Report>(r => {
            _sessionReport = r;
            SessionData.SetupGet(s => s.TheReport).Returns(_sessionReport);
       });

    Esto asegura que el valor devuelto por el método Get se mantiene siempre en sintonía con la anterior llamada al método set. Y nos lleva a algo que (funcionalmente) se comporta como:-

    public Report Report {
        set {
           //Sets the field on the test class
           _reportCopy = value;
        }
        get { 
           //Copy of the value of the _report reference field in your test class
           return _reportCopy; 
        }  
    }
  2. 11

    Me parece muy/demasiado complicado de poner un SetupGet dentro de SetupSet aplicación.

    Sería más fácil .Devolución de un delegado, por lo que es evaluado cada vez que, en lugar de simplemente devuelve una copia de la referencia.

    Algo como esto es mucho más fácil en el ojo (y debería funcionar mejor ya no estás continuamente re-definición de la función de captador).

    SessionData
       .SetupSet(s => s.TheReport = It.IsAny<Report>())
       .Callback<RDLDesigner.Common.Report>(r => _sessionReport = r);    
    SessionData
       .SetupGet(s => s.TheReport).Returns(() => _sessionReport);

Dejar respuesta

Please enter your comment!
Please enter your name here