Soy nuevo en Moq. Me estoy burlando de una clase PagingOptions . Así es como se ve la clase:
public class PagingOptions { [Range(1, 99999, ErrorMessage = "Offset must be greater than 0.")] public int? Offset { get; set; } [Range(1, 100, ErrorMessage = "Limit must be greater than 0 and less than 100.")] public int? Limit { get; set; } public PagingOptions Replace(PagingOptions newer) { return new PagingOptions { Offset = newer.Offset ?? Offset, Limit = newer.Limit ?? Limit }; } }Aquí está mi versión simulada de la clase,
var mockPagingOptions = new Mock<PagingOptions>(); mockPagingOptions.Setup(po => po.Limit).Returns(25); mockPagingOptions.Setup(po => po.Offset).Returns(0);Recibo el siguiente error al configurar los valores de propiedad. ¿Estoy haciendo algo mal? Parece que no puedo Moq clase concreta? ¿Solo se pueden burlar las interfaces? Por favor asiste.
Gracias, Abdul
Moq crea una implementación del tipo simulado. Si el tipo es una interfaz, crea una clase que implementa la interfaz. Si el tipo es una clase, crea una clase heredada y los miembros de esa clase heredada llaman a la clase base. Pero para hacer eso tiene que anular a los miembros. Si una clase tiene miembros que no se pueden anular (no son virtuales, abstractos), Moq no puede anularlos para agregar sus propios comportamientos.
En este caso, no hay necesidad de burlarse de PagingOptions porque es fácil usar uno real. En lugar de esto:
var mockPagingOptions = new Mock<PagingOptions>(); mockPagingOptions.Setup(po => po.Limit).Returns(25); mockPagingOptions.Setup(po => po.Offset).Returns(0);Hacer esto:
var pagingOptions = new PagingOptions { Limit = 25, Offset = 0 };¿Cómo determinamos si burlarnos o no de algo? En términos generales, nos burlamos de algo si no queremos incluir la implementación concreta del tiempo de ejecución en nuestra prueba. Queremos probar una clase, no ambas al mismo tiempo.
Pero en este caso, PagingOptions es solo una clase que contiene algunos datos. Realmente no tiene sentido burlarse de él. Es igual de fácil usar la cosa real.
Tuve el mismo error, pero en mi caso estaba tratando de burlarme de la clase en sí y no de su interfaz:
// Mock<SendMailBLL> sendMailBLLMock = new Mock<SendMailBLL>(); // Wrong, causes error. Mock<ISendMailBLL> sendMailBLLMock = new Mock<ISendMailBLL>(); // This works. sendMailBLLMock.Setup(x => x.InsertEmailLog( It.IsAny<List<EmailRecipient>>(), It.IsAny<List<EmailAttachment>>(), It.IsAny<string>()));Quiero mejorar la respuesta de Scott y dar una respuesta general.
Si el tipo es una clase, crea una clase heredada y los miembros de esa clase heredada llaman a la clase base. Pero para hacer eso tiene que anular a los miembros. Si una clase tiene miembros que no se pueden anular (no son virtuales, abstractos), Moq no puede anularlos para agregar sus propios comportamientos.
En mi situación, tuve que hacer que el accesorio fuera virtual. Así que la respuesta a tu código de clase es:
public class PagingOptions { [Range (1, 99999, ErrorMessage = "Offset must be greater than 0.")] public virtual int? Offset { get; set; } [Range (1, 100, ErrorMessage = "Limit must be greater than 0 and less than 100.")] public virtual int? Limit { get; set; } public PagingOptions Replace (PagingOptions newer) { return new PagingOptions { Offset = newer.Offset ?? Offset, Limit = newer.Limit ?? Limit }; } }usa lo mismo:
var mockPagingOptions = new Mock<PagingOptions>(); mockPagingOptions.Setup(po => po.Limit).Returns(25); mockPagingOptions.Setup(po => po.Offset).Returns(0);En caso de que haya llegado a esta pregunta según el título original Non-overridable members may not be used in setup / verification expressions y ninguna de las otras respuestas le haya ayudado, es posible que desee ver si la reflexión puede satisfacer sus necesidades de prueba.
Suponga que tiene una clase Foo con una propiedad definida como public int I { get; private set; }
Si prueba los diversos métodos en las respuestas aquí, algunos de ellos funcionarán para este escenario. Sin embargo, puede usar la reflexión .net para configurar un valor de una variable de instancia y aún así mantener un soporte de refactorización bastante bueno en el código.
Aquí hay un fragmento que establece una propiedad con un setter privado :
var foo = new Foo(); var I = foo.GetType().GetProperty(nameof(Foo.I), BindingFlags.Public | BindingFlags.Instance); I.SetValue(foo, 8675309);No recomiendo esto para el código de producción. Me ha resultado muy útil en numerosas pruebas. Encontré este enfoque hace algunos años, pero necesitaba volver a buscarlo recientemente y este fue el resultado de búsqueda principal.