Comments (16)
Generic allows to use one test method for different types (see sample below).
Sample: Use one method TestGenericForArbitraryArray for double and int arrays, instead of 2 methods TestDoubleForArbitraryArray and TestIntForArbitraryArray for each type.
[TestFixture]
public class TheorySampleTests
{
[Datapoint]
public double[,] Array2X2Double = new double[,] { { 1, 0 }, { 0, 1 } };
[Datapoint]
public int[,] Array2X2Int = new int[,] { { 1, 0 }, { 0, 1 } };
[Theory]
public void TestDoubleForArbitraryArray(double[,] array)
{
Console.WriteLine("TestDoubleForArbitraryArray()");
// ...
}
[Theory]
public void TestIntForArbitraryArray(int[,] array)
{
Console.WriteLine("TestIntForArbitraryArray()");
// ...
}
[Theory]
public void TestGenericForArbitraryArray<T>(T[,] array)
{
Console.WriteLine("TestGenericForArbitraryArray()");
// ...
}
}
from nunit.
@constructor-igor This seems like a logical workaround. The OP wanted the generic method to pick up all data that could possibly satisfy the generic method. I'm not sure that's really feasible here. I think it would probably work in a generic fixture, where T would actually mean a specific type.
from nunit.
@CharliePoole, please, could you help me to understand how can I help in the issue (status:confirm)?
from nunit.
The first step would be to verify that the failure actually occurs. As I commented a while back, it makes sense that NUnit can't find an open generic type. Next would be to create some tests to show exactly what does and doesn't work. You got a good start at that. I think your first and second methods work, but the third does not find any data. Right?
A further step would be to see what happens in a generic fixture, where the method itself uses T but is no longer generic. I am guessing that it would work and would find the specific int or double data.
If we can lay it all out, then we know it's truly a bug. If you want to work on it, we will have to decide how much to fix and how much to simply document.
Is that enought to help you get started?
from nunit.
original test can be reproduced in nunit v3 Beta1
[TestFixture]
public class TheorySampleTests
{
[Datapoint]
public double[] ArrayDouble = { 0, 1, 2, 3 };
[Datapoint]
public int[] ArrayInt = { 0, 1, 2, 3 };
[Theory]
public void TestDoubleForArbitraryArray(double[] array)
{
Console.WriteLine("TestDoubleForArbitraryArray()");
TestGenericForArbitraryArray(array);
}
[Theory]
public void TestIntForArbitraryArray(int[] array)
{
Console.WriteLine("TestIntForArbitraryArray()");
TestGenericForArbitraryArray(array);
}
[Theory]
public void TestGenericForArbitraryArray<T>(T[] array)
{
Console.WriteLine("TestGenericForArbitraryArray()");
// ...
}
}
Test Name: TestGenericForArbitraryArray
Test FullName: NUnit_v3_samples.TheorySampleTests.TestGenericForArbitraryArray
Test Source: \NUnit_v3_samples\TheorySampleTests.cs : line 58
Test Outcome: Failed
Test Duration: 0:00:00.001
Result Message: No arguments were provided
from nunit.
Found next workaround: base class with generic test method and number (per type) of test classes
public class TheorySampleTestsBasic<T>
{
[Theory]
public void TestGenericForArbitraryArray(T[] array)
{
Console.WriteLine("TestGenericForArbitraryArray()");
}
}
[TestFixture]
public class TheorySampleTestsChildDouble : TheorySampleTestsBasic<double>
{
[Datapoint]
public double[] ArrayDouble1 = { 0, 1, 2, 3 };
[Datapoint]
public double[] ArrayDouble2 = { 4, 5, 6, 7 };
}
[TestFixture]
public class TheorySampleTestsChildInt : TheorySampleTestsBasic<int>
{
[Datapoint]
public int[] ArrayDouble1 = { 0, 1, 2, 3 };
[Datapoint]
public int[] ArrayDouble2 = { 4, 5, 6, 7 };
}
from nunit.
What if you make the generic class a generic fixture, eliminating the derived classes and moving all the datapoints into the one class? The generic fixture could have [TestFixture(typeof(int))] and [TestFixture(typeof(double))] attributes.
from nunit.
ok.
Next way checked: seems works correctly.
[TestFixture(typeof(int))]
[TestFixture(typeof(double))]
public class TheorySampleTestsGeneric<T>
{
[Datapoint]
public double[] ArrayDouble1 = { 0, 1, 2, 3 };
[Datapoint]
public double[] ArrayDouble2 = { 4, 5, 6, 7 };
[Datapoint]
public int[] ArrayInt = { 0, 1, 2, 3 };
[Theory]
public void TestGenericForArbitraryArray(T[] array)
{
Console.WriteLine("TestGenericForArbitraryArray()");
}
}
by the way, Resharper v8 doesn't work correct for the use case:
from nunit.
Yes, so the bug is really that it doesn't work for Generic methods. When the class is generic, then that method is no longer a generic because T has already been resolved to int or double. I changed the title accordingly.
from nunit.
So do you think we should "fix" this or just document it?
For the original example to work, NUnit would have to find all Datapoints of any type and try to use them for the method. That seems a bit extreme.
Another option would be to give Theory an optional type argument, so that the theory was instantiated multiple times, just as we do for a TestFixture. IOW, we would have [Theory(typeof(int))] and [Theory(typeof(double))] in this case. Is that desirable?
Finally, as I say, we could just document what works and what doesn't on the TheoryAttribute page.
from nunit.
I guess, the issue should be supported ("fixed").
In my opinion, if compiler can understand and call generic method (see sample below), then developer expects same behavior in "Theory" attribute.
[TestFixture]
public class TheorySampleTests
{
[Datapoint]
public double[] ArrayDouble = { 0, 1, 2, 3 };
[Datapoint]
public int[] ArrayInt = { 0, 1, 2, 3 };
[Theory]
public void TestDoubleForArbitraryArray(double[] array)
{
Console.WriteLine("TestDoubleForArbitraryArray()");
TestGenericForArbitraryArray(array);
}
[Theory]
public void TestIntForArbitraryArray(int[] array)
{
Console.WriteLine("TestIntForArbitraryArray()");
TestGenericForArbitraryArray(array);
}
private void TestGenericForArbitraryArray<T>(T[] array)
{
Console.WriteLine("TestGenericForArbitraryArray()");
}
}
from nunit.
Thanks for checking this out. I think we need to figure out just what to support here, so I'm flagging it as status:design. We use that label when we don't want anyone to just start coding, without first having an agreed-upon specification. In this case, I think we have choices ranging from most complete implementation down to no implementation at all:
- NUnit could search for data points of every type that can be used to instantiate the theory. It would have to honor any constraints on the type parameters, which would be new code for us. This approach would be challenging but definitely possible. The main drawback is that it might make generic Theories less useful. The user could not define datapoints in the class of any type that should not be used for this Theory. Requires some thought and some sample code.
- We could give TheoryAttribute a type parameter and have the user specify exactly what instances of the Theory should be tested. In our example, we would use [Theory(typeof(int))] and [Theory(typeof(double))] to explicitly cause the theory to be used twice. This would probably be a somewhat easier implementation and we would be treating TheoryAttribute in the same way we currently handle TestFixtureAttribute.
- We could simply document the limitation. Rather than generic Theories, users should use a generic class to contain the Theory.
These issues are not mutually exclusive. We also could:
- Do both 1 and 2.
- Do 3 first, then follow up with 1, 2 or 4.
This issue interacts with #150 and with the fix already made for #377. We should review it in light of those issues as well.
We can discuss which way to go here. Once we set a direction, we should post it here and remove the design status.
from nunit.
The documentation has been updated to indicate that generic methods may not be used and explaining the workaround using a generic fixture: https://github.com/nunit/nunit/wiki/Theory-Attribute
I'm moving this issue out of the beta 2 milestone so we can decide which way to go in the next release.
from nunit.
Looking at the options, I lean towards giving TheoryAttribute a Type argument. Finding all possible types that can be used seems like a step too far in making decisions for the user. Just as the programmer writes [TestFixture(typeof(int))] to determine how a generic fixture will be instantiated, they can write [Theory(typeof(int))] for a generic theory. The above example would then be handled like this:
[TestFixture]
public class TheorySampleTests
{
[Datapoint]
public double[] ArrayDouble1 = { 0, 1, 2, 3 };
[Datapoint]
public double[] ArrayDouble2 = { 4, 5, 6, 7 };
[Datapoint]
public int[] ArrayInt = { 0, 1, 2, 3 };
[Theory(typeof(int))]
[Theory(typeof(double))]
public void TestGenericForArbitraryArray(T[] array)
{
Console.WriteLine("TestGenericForArbitraryArray()");
}
}
@nunit/core-team What do you think of this approach versus the other? Should this stay in the 3.0 release as a feature? What priority?
from nunit.
I like this alternative. I would be fine with leaving it in 3.0, but I think that it should be low priority for the release. I think we should be concentrating on core-vision type issues for the 3.0 release so we can get it out there and widely used, and then start adding features.
from nunit.
OK, I'm making it low and leaving it in the 3.0 milestone. It could just as well end up pushed to 'future'.
from nunit.
Related Issues (20)
- Patch-Release 4.0.2 HOT 5
- Implement API for composable and reusable test setups HOT 2
- Remove link in readme to the google discuss group, it's spammed.
- Generic TestCase and TestCaseParameter support
- NUnit publish plugin for Jenkins doesn't create attachments file HOT 3
- CollectionAssert (mis)handling of IList implementation HOT 8
- System.Net.Sockets.SocketException : An existing connection was forcibly closed by the remote host --SocketException HOT 10
- `ValueTask` is not being properly consumed by the `AwaitAdapter` HOT 4
- Non-static TestCaseSource/ValueSource HOT 1
- Nunit 4 VsCode .Net 8 HOT 10
- Switch to using MacOS 14 in GitHub Actions
- Switch back to using macos-latest after latest becomes MacOS 14 HOT 3
- After upgrade from version 3.14.0 to 4.* running multiple test categories in parentheses separated with 'OR' stopped working HOT 3
- Additional Test Events for OneTimeSetUp / OneTimeTearDown HOT 20
- Allow specific tests to not run in parallel with each other but to run in parallel with other tests HOT 2
- Apartment attribute ignored when .runsettings contains DefaultTimeout HOT 33
- TestCaseSource that contains Exception with InnerException - not running tests HOT 9
- Add custom conditions on `[IgnoreAttribute]` HOT 2
- Analyzer message NUnit2005 is indeed extremely annoying HOT 4
- StringAssert.IsNullOrEmpty overloads HOT 6
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from nunit.