valores tipo reciben que programacion pasar pasaje parametros parametro objetos objeto metodos metodo funciones como c# unit-testing xunit xunit.net

c# - tipo - Pasar parámetros complejos a



pasar un objeto a un metodo en c# (5)

Xunit tiene una buena característica : puede crear una prueba con un atributo de Theory y poner datos en atributos InlineData , y xUnit generará muchas pruebas y las probará todas.

Quiero tener algo como esto, pero los parámetros de mi método no son ''datos simples'' (como string , int , double ), sino una lista de mi clase:

public static void WriteReportsToMemoryStream( IEnumerable<MyCustomClass> listReport, MemoryStream ms, StreamWriter writer) { ... }


Crear matrices de objetos anónimos no es la forma más fácil de construir los datos, así que utilicé este patrón en mi proyecto

Primero defina algunas clases compartidas reutilizables

//http://.com/questions/22093843 public interface ITheoryDatum { object[] ToParameterArray(); } public abstract class TheoryDatum : ITheoryDatum { public abstract object[] ToParameterArray(); public static ITheoryDatum Factory<TSystemUnderTest, TExecptedOutput>(TSystemUnderTest sut, TExecptedOutput expectedOutput, string description) { var datum= new TheoryDatum<TSystemUnderTest, TExecptedOutput>(); datum.SystemUnderTest = sut; datum.Description = description; datum.ExpectedOutput = expectedOutput; return datum; } } public class TheoryDatum<TSystemUnderTest, TExecptedOutput> : TheoryDatum { public TSystemUnderTest SystemUnderTest { get; set; } public string Description { get; set; } public TExecptedOutput ExpectedOutput { get; set; } public override object[] ToParameterArray() { var output = new object[3]; output[0] = SystemUnderTest; output[1] = ExpectedOutput; output[2] = Description; return output; } }

Ahora su prueba individual y los datos de los miembros son más fáciles de escribir y más limpios ...

public class IngredientTests : TestBase { [Theory] [MemberData(nameof(IsValidData))] public void IsValid(Ingredient ingredient, string testDescription, bool expectedResult) { Assert.True(ingredient.IsValid == expectedResult, testDescription); } public static IEnumerable<object[]> IsValidData { get { var food = new Food(); var quantity = new Quantity(); var data= new List<ITheoryDatum>(); data.Add(TheoryDatum.Factory(new Ingredient { Food = food } , false, "Quantity missing")); data.Add(TheoryDatum.Factory(new Ingredient { Quantity = quantity } , false, "Food missing")); data.Add(TheoryDatum.Factory(new Ingredient { Quantity = quantity, Food = food } , true, "Valid")); return data.ConvertAll(d => d.ToParameterArray()); } } }

La propiedad Description cadena es tirarse un hueso cuando falla uno de sus muchos casos de prueba


Hay muchos atributos xxxxData en XUnit. Vea, por ejemplo, el atributo PropertyData .

Puede implementar una propiedad que devuelva IEnumerable<object[]> . Cada uno de los object[] que este método genera se "desempaquetarán" como parámetros para una sola llamada a su método [Theory] .

Otra opción es ClassData , que funciona igual, pero permite compartir fácilmente los ''generadores'' entre pruebas en diferentes clases / espacios de nombres, y también separa los ''generadores de datos'' de los métodos de prueba reales.

Ver, por ejemplo, estos ejemplos de aquí :

Ejemplo de PropertyData

public class StringTests2 { [Theory, PropertyData(nameof(SplitCountData))] public void SplitCount(string input, int expectedCount) { var actualCount = input.Split('' '').Count(); Assert.Equal(expectedCount, actualCount); } public static IEnumerable<object[]> SplitCountData { get { // Or this could read from a file. :) return new[] { new object[] { "xUnit", 1 }, new object[] { "is fun", 2 }, new object[] { "to test with", 3 } }; } } }

Ejemplo de ClassData

public class StringTests3 { [Theory, ClassData(typeof(IndexOfData))] public void IndexOf(string input, char letter, int expected) { var actual = input.IndexOf(letter); Assert.Equal(expected, actual); } } public class IndexOfData : IEnumerable<object[]> { private readonly List<object[]> _data = new List<object[]> { new object[] { "hello world", ''w'', 6 }, new object[] { "goodnight moon", ''w'', -1 } }; public IEnumerator<object[]> GetEnumerator() { return _data.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } }


Para actualizar la respuesta de [MemberData] : El atributo [PropertyData] ha sido reemplazado por [MemberData] que toma como argumento el nombre de la cadena de cualquier método, campo o propiedad estática que devuelva IEnumerable<object[]> . (Me parece particularmente agradable tener un método de iterador que pueda calcular los casos de prueba de uno en uno, dejándolos a medida que se computan).

Cada elemento en la secuencia devuelta por el enumerador es un object[] y cada matriz debe tener la misma longitud y esa longitud debe ser el número de argumentos para su caso de prueba (anotado con el atributo [MemberData] y cada elemento debe tener el mismo escriba como el parámetro del método correspondiente. (O tal vez pueden ser tipos convertibles, no lo sé).

(Consulte las notas de la versión de xUnit.net de marzo de 2014 y el parche real con el código de ejemplo ).


Puedes intentarlo de esta manera:

public class TestClass { bool isSaturday(DateTime dt) { string day = dt.DayOfWeek.ToString(); return (day == "Saturday"); } [Theory] [MemberData("IsSaturdayIndex", MemberType = typeof(TestCase))] public void test(int i) { // parse test case var input = TestCase.IsSaturdayTestCase[i]; DateTime dt = (DateTime)input[0]; bool expected = (bool)input[1]; // test bool result = isSaturday(dt); result.Should().Be(expected); } }

Crea otra clase para contener los datos de prueba:

public class TestCase { public static readonly List<object[]> IsSaturdayTestCase = new List<object[]> { new object[]{new DateTime(2016,1,23),true}, new object[]{new DateTime(2016,1,24),false} }; public static IEnumerable<object[]> IsSaturdayIndex { get { List<object[]> tmp = new List<object[]>(); for (int i = 0; i < IsSaturdayTestCase.Count; i++) tmp.Add(new object[] { i }); return tmp; } } }


Supongo que te equivocas aquí. Qué significa xUnit Theory attribute realmente significa: desea probar esta función enviando valores especiales / aleatorios como parámetros que recibe esta función bajo prueba. Eso significa que lo que defina como el siguiente atributo, como: InlineData , PropertyData , ClassData , etc. será la fuente de esos parámetros. Eso significa que debe construir el objeto fuente para proporcionar esos parámetros. En tu caso, supongo que deberías usar el objeto ClassData como fuente. Además, tenga en cuenta que ClassData hereda de: IEnumerable<> , esto significa que cada vez que se use otro conjunto de parámetros generados como parámetros entrantes para la función bajo prueba hasta que IEnumerable<> produzca valores.

Ejemplo aquí: Tom DuPont .NET

El ejemplo puede ser incorrecto: no utilicé xUnit durante mucho tiempo