I need help with writing unit test with xunit. I am trying to test a validation where array length cannot be greater than 20MB
[Theory]
[InlineData((arrayGreaterThan20MB())]
public void Fail_when_documentSize_is_greater(byte[] documentSize)
{
_getAccountFileViewModel.Content = documentSize;
}
Private Function
private static byte[] arrayGreaterThan20MB()
{
byte[] arr = new byte[5000000000];
return arr;
}
I am not sure what is the best way to test this. I am getting a error when I am trying to pass function in inline data.
Error "An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type"
Just declare the array within the test itself, instead of trying to pass via inline data attribute
[Theory]
public void Fail_when_documentSize_is_greater() {
byte[] overSizedDocument = new byte[5000000000];
_getAccountFileViewModel.Content = overSizedDocument;
//...
}
You can not use the result of a method call as parameter of an attribute. That's what the error is telling you. You can only pass constants or literals. For example like this:
[Theory]
[InlineData("a", "b")]
public void InlineDataTest(string first, string second)
{
Assert.Equal("a", first);
Assert.Equal("b", second);
}
XUnit has some other attributes, that can help you here. E.g. there is the MemberData attribute, that allows you to specify a method name of a method that provides the test data. Note that it returns an IEnumerable of object array. Each object array will be used to call the test method once. The content of the object array are the parameters. For example:
[Theory]
[MemberData(nameof(DataGeneratorMethod))]
public void MemberDataTest(string first, string second)
{
Assert.Equal("a", first);
Assert.Equal("b", second);
}
public static IEnumerable<object[]> DataGeneratorMethod()
{
var result = new List<object[]>(); // each item of this list will cause a call to your test method
result.Add(new object[] {"a", "b"}); // "a" and "b" are parameters for one test method call
return result;
// or
// yield return new object[] {"a", "b"};
}
In the case you mentioned above, the simplest way would be just to call your method that creates the test data within your test method.
[Theory]
public void Fail_when_documentSize_is_greater()
{
_getAccountFileViewModel.Content = arrayGreaterThan20MB();
}
There is another attribute called ClassData that can use a data generator class.
More detailed information can be found on this blog post
Related
I have a test class and I want write a test for one of my functions and I have to use HashSet in [Theory] inlineData but I can't use it.
[Theory]
[InlineData(new HashSet<string>() {"text1","text2"}, "str")]
public void BuildInvertedIndexTest(ISet<string> expectedDocContain, string searchingWord)
I wrote classData and memberData but It wasn't successful.
please guide me.
With MemberDataAttribute the solution could look like this:
public static IEnumerable<object[]> BuildInvertedIndexTestData()
{
yield return new object[] { new HashSet<string>() { "text1", "text2" }, "str" };
yield return new object[] { ... };
}
The usage would look like this:
[Theory, MemberData(nameof(BuildInvertedIndexTestData))]
public void BuildInvertedIndexTest(ISet<string> expectedDocContain, string searchingWord)
I haven't tested this solution so it might happen that you need to change the expectedDocContain parameter's type to HashSet<string>.
You cannot use HashSet<T> with [InlineData] as attributes only support simple types like string, int, bool, arrays etc.
You will need to use another way of parameterising the test, such as [MemberData] for ISet<T>/HashSet<T> which you can read more about in this blog post by Andrew Lock: https://andrewlock.net/creating-parameterised-tests-in-xunit-with-inlinedata-classdata-and-memberdata/
Alternatively, you could use a string[] with [InlineData] and construct the HashSet<string> from that in the body of the test.
[Theory]
[InlineData(new string[] {"text1","text2"}, "six")]
public void BuildInvertedIndexTest(string[] expectedDocContain, string searchingWord)
{
var hashSet = new HashSet<string>(expectedDocContain);
// TODO Put the rest of your test here.
}
I'm currently building a Test Project and I need to pass several arguments to the test function. Because I need to call the test function with different parameter sets I decided to use ms-test with the [DataTestMethod].
Now I need to pass jagged arrays as Parameters to the function.
But I don't get it to work.
The call for TestMethod1 is working.
The call for TestMethod2 is not working as it is not successfully compiling.
CS0182:
An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace UnitTestProject2
{
[TestClass]
public class UnitTest1
{
[DataTestMethod]
[DataRow(new int[] { })]
public void TestMethod1(int[] values)
{
}
[DataTestMethod]
[DataRow(new int [][] { } )]
public void TestMethod2(int[][] values)
{
}
}
}
Does anyone has any suggestion to get this working?
Sadly I need to use some kind of two dimension data type because I need to pass information about two loops inside of the test function. I can't use the params keyword because I need two of this jagged arrays in the test function.
Regards
White
You cannot use jagged array as a parameter in an attribute, because you cannot declare it as a const. More explanation in here: Const multi-dimensional array initialization
For your purpose I would use DynamicDataAttribute:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
namespace UnitTestProject
{
[TestClass]
public class TestClass
{
static IEnumerable<int[][][]> GetJaggedArray
{
get
{
return new List<int[][][]>
{
new int[][][]
{
new int [][]
{
new int[] { 1 },
new int[] { 2, 3, 4 },
new int[] { 5, 6 }
}
}
};
}
}
[TestMethod]
[DynamicData(nameof(GetJaggedArray))]
public void Test1(int[][] jaggedArray)
{
Assert.AreEqual(1, jaggedArray[0][0]);
Assert.AreEqual(2, jaggedArray[1][0]);
Assert.AreEqual(3, jaggedArray[1][1]);
Assert.AreEqual(4, jaggedArray[1][2]);
Assert.AreEqual(5, jaggedArray[2][0]);
Assert.AreEqual(6, jaggedArray[2][1]);
}
}
}
I know that syntax IEnumerable<int[][][]> is not pleasant for eyes, but since DynamicDataAttribute.GetData(MethodInfo) method is returning IEnumerable<object[]>, and your object is int[][], this is what you get.
All methods in the "ProbabilitiesTheory" class accept dynamic count of parameters - it means that there can be put as many parameters as one wants. But .NET still says "System.Reflection.TargetParameterCountException" when invoking a method, that has "params" keyword in its parameters.
Here's the code:
internal static class ProbabilitiesTheory
{
static public double GetMediumValue(params double[] integers)
{ }
}
class Program
{
static void Main(string[] args)
{
MethodInfo[] methods = Type.GetType("ConsoleApplication1.ProbabilitiesTheory").GetMethods();
while (true)
{
Console.WriteLine("Write the name of the method\n");
string NameOfMethod = Console.ReadLine();
Console.WriteLine("Write the parameters of the method using the following format:
parameter1;parameter2;parameter3;parameterN\n");
string ParametersOfMethod = Console.ReadLine();
foreach (var i in methods)
{
if (i.Name == NameOfMethod)
{
object[] #parameters = (from t in ParametersOfMethod.Split(';') where t != "" select (object)Convert.ToDouble(t)).ToArray();
i.Invoke(null, #parameters); // Exception HERE
}
}
Console.WriteLine("______");
}
}
}
It is absolutely ok with LINQ expression there, i get what i need to get: object[] containing dynamic amount of double values.
How do i solve this problem?
As far as reflection is concerned, a params array is just an array with a fancy syntactical sugar. You could solve the immediate problem for most of your methods by adjusting your code like so:
double[] #parameters = (from t in ParametersOfMethod.Split(';') where t != "" select Convert.ToDouble(t)).ToArray();
i.Invoke(null, new[] { #parameters});
The gist of this is that a params array is just a single parameter at run-time, and the ability to add a variable amount of values to it is just a nicety done by the compiler.
You can confirm this with a snippet like this:
void Main()
{
var parameterCount = typeof(Test).GetMethod("Foo").GetParameters().Count();
Console.WriteLine(parameterCount); // Output: 2
}
// Define other methods and classes here
public static class Test
{
public static void Foo(double x, params double[] y)
{}
}
If you need to invoke a function that uses a params array with user provided values when the params array is not the only parameter, you're going to need to get the method parameter count and work out where the array actually starts, then wrap things accordingly.
I want to write an extension methods for compare some proprties of two objects. I wrote this code:
public static void AreTwoObjectsEqual(this Assert asr, object Actual, object Expected, List<string> FieldsMustCheck)
{
foreach (string item in FieldsMustCheck)
{
if (Actual.GetType().GetProperty(item) == null || Expected.GetType().GetProperty(item) == null)
{
throw new Exception("Property with name : " + item + " not found in objects ");
}
var ActualPropertyValue = Actual.GetType().GetProperty(item).GetValue(Actual, null);
var ExpectedPropertyValue = Expected.GetType().GetProperty(item).GetValue(Expected, null);
if (ActualPropertyValue != ExpectedPropertyValue)
{
throw new AssertFailedException("Test failed for propery : " + item);
}
}
}
when I want to build the project I get this error:
'Microsoft.VisualStudio.TestTools.UnitTesting.Assert': static types cannot be used as parameters
Can any one help me remove this error.Thanks
Well the compiler error message is fairly clear: Assert is a static class, so you can't use that as the parameter type for the extension method. It's not clear why you wanted to in the first place, to be honest. If you were hoping to be able to use Assert.AreTwoObjectsEqual, you just can't do that - extension methods are meant to mimic instance methods, not static methods in a different type.
I suspect you should just create a static class of your own, e.g. MoreAssert, and just make it a normal static method:
public static class MoreAssert
{
public static void AreEqualByProperties(object expected, object actual,
List<string> propertyNames)
{
...
}
}
Parameter names changed to comply with .NET naming conventions. I'd strongly encourage you to use camelCase names for local variables, too. I've also reordered the parameters to be consistent with the other assertions.
So then you'd just call:
MoreAssert.AreEqualByProperties(...);
You might also consider using params string[] propertyNames instead of List<string> propertyNames to make it easier to call.
I would like to pass some parameters to a web method as an array. The web method's signature does not have the params keyword.
I have a variable number of parameters (as the web method accepts) so I cannot put the array into n single variables.
How can this be done?
params is just syntactic sugar, why not just do something like this:
var myWebService = new MyWebService();
myWebService.MyMethod(new string[] { "one", "two", "three" });
The method signature on the web service side would just be:
public void MyMethod(string[] values);
If you post your web method maybe I can provide a better answer.
EDIT
If you can't modify the web method signature, then I would use an extension method to wrap the difficult to call web service. For example, if our web service proxy class looks like:
public class MyWebService
{
public bool MyMethod(string a1, string a2, string a3, string a4, string a5,
string a6, string a7, string a8, string a9, string a10)
{
//Do something
return false;
}
}
Then you could create an extension method that accepts the string array as params and makes the call to MyWebService.
public static class MyExtensionMethods
{
public static bool MyMethod(this MyWebService svc, params string[] a)
{
//The code below assumes you can pass in null if the parameter
//is not specified. If you have to pass in string.Empty or something
//similar then initialize all elements in the p array before doing
//the CopyTo
if(a.Length > 10)
throw new ArgumentException("Cannot pass more than 10 parameters.");
var p = new string[10];
a.CopyTo(p, 0);
return svc.MyMethod(p[0], p[1], p[2], p[3], p[4], p[5],
p[6], p[7], p[8], p[9]);
}
}
You could then call your web service using the extension method you created (just be sure to add a using statment for the namespace where you declared you extension method):
var svc = new MyWebService();
svc.MyMethod("this", "is", "a", "test");
Why don't you use..an array?
[WebMethod]
public string Foo(string[] values)
{
return string.Join(",", values);
}
Ignore the fact that it is a web method for a moment. Ultimately, it is a method. And like all methods, is either defined to take parameters or not. If it is not defined to take parameters, then you can't pass parameters to it, can you? Not unless you have access to the source code and are able to chance it's definition.
If it is defined to take parameters, then the question is, is it defined to take array parameters or not? If not, then you can't pass parameters to it (not unless you can change it so that it can.)