Equivalent of generic NUnit.Framework.TestFixture in xUnit - xunit

In NUnit, we can create a generic test fixture.
[TestFixture(typeof(double))]
[TestFixture(typeof(float))]
public class ServiceTests<T>
{
private readonly MyService<T> myService = new();
/* ... */
}
Has xUnit any equivalent of this?
I'm trying to test a generic service and now I need to create separate classes to test it for many generic types.
public abstract class DoubleServiceTests : ServiceTests<double>
{}
public abstract class FloatServiceTests : ServiceTests<float>
{}
public abstract class ServiceTests<T>
{
private readonly MyService<T> myService = new();
/* ... */
}
This is a solution that I'm currently using.

Maybe usage of Theory attribute will help.
Theory allows injection of test data inside a test. So some test from ServiceTests may look like this:
[Theory]
[InlineData(typeof(float))]
[InlineData(typeof(double))]
public void SomeTestMethod(Type t)
{
// make use of type t
}
More [info] on Theory related attributes in xunit.

Related

Class fixture type 'SetupFixture' had one or more unresolved constructor arguments [duplicate]

I am using XUnit and need to perform some action before running a test suit. so, I try to use IClassFixture feature of XUnit. but I cannot find a way to inject dependencies into the Fixture class. my code structure is such as below:
public class MyFixture
{
IDependency _dep;
public MyFixture(IDependency dep)
{
_dep = dep;
}
void DoSomeJob()
{
//// some code there
dep.DoSome();
}
}
And this is my test class code:
public class MyTest : IClassFixture<MyFixture>
{
[Fact]
public void test_my_code()
{
////simply just test the code
}
}
but when I run the test I am getting the exception
Xunit.Sdk.TestClassException Class fixture type 'MyFixture' had one or more unresolved constructor
Your Fixture class depends on IDependency dep, which has not been configured. You could use the Fixture class to setup a service provider; However it is not the best solution, as you have to end up using service locator patter such as
serviceProvider.GetRequiredService<T>()
Suggest to use xunit.di, it is an extension built into xunit framework to support constructor dependency injection, which allows us to achieve Inversion of Control (IoC) between test classes and their dependencies.
Install-Package Xunit.Di
To use xunit.di:
Install the xunit.di nuget package
Create a Setup.cs class to configure dependencies, (optional) and inherits the Xunit.Di.Setup.cs
Configure dependencies in the Setup.cs class.
Find full instructions and demos from xunit.di GET-STARTED
Your test project has the following:
Setup class that has a public IServiceProvider, which configures all the dependencies
Test class with constructor injecting the dependencies
Your Setup.cs class looks like below:
private IServiceProvider _services;
private bool _built = false;
private readonly IHostBuilder _defaultBuilder;
public Setup()
{
_defaultBuilder = Host.CreateDefaultBuilder();
}
public IServiceProvider Services => _services ?? Build();
private IServiceProvider Build()
{
if (_built)
throw new InvalidOperationException("Build can only be called once.");
_built = true;
_defaultBuilder.ConfigureServices((context, services) =>
{
services.AddSingleton<TextReaderService>();
services.AddSingleton<IDependency, DependencyImpl>();
// where DependencyImpl implements IDependency
// ... add other services needed
});
_services = _defaultBuilder.Build().Services;
return _services;
}
Then your test class looks like below:
public class MyTest
{
private readonly IDependency _dependency;
public MyTest(IDependency dependency)
{
_dependency = dependency;
}
[Fact]
public void test_my_code()
{
var result = _dependency.DoStuff();
Assert.NotNull(result);
////simply just test the code
}
}

Should I use dependency injection to bring in a class with constants into my Xamarin Forms application or is there a better way?

I have a class containing constants:
namespace Test.AppService
{
public static class Const
{
public const bool Tmr = false;
public const int Pti = 10;
...
I was wondering if this would be a good candidate for dependency injection or would it be better to leave it as it is and just add using for Test.AppService into every page? Would appreciate advice on this.
Reading your comment about needing to use a different set of constants if that is something you see happening then Dependency injection makes sense. For example if you are using different environments like DEV, QA, Release comes to mind.
You would need to declare an interface with all your public fields. Implement that Interface in different classes with all the possible different scenarios. Then you can register your interface and the class with your desired set of values that you would be able to swap as needed.
For example:
public interface IConfiguration
{
public string ConnectionString {get;}
}
public class QaValues : IConfiguration
{
public string ConnectionString
{ get
{
return "qaconnection";
}
}
}
public class ReleaseValues : IConfiguration
{
public string ConnectionString
{ get
{
return "releaseconnection";
}
}
}
DependencyService.Register<IConfiguration,QaValues>();

How do I mock an autowired #Value field in Spring with Mockito?

I'm using Spring 3.1.4.RELEASE and Mockito 1.9.5. In my Spring class I have:
#Value("#{myProps['default.url']}")
private String defaultUrl;
#Value("#{myProps['default.password']}")
private String defaultrPassword;
// ...
From my JUnit test, which I currently have set up like so:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({ "classpath:test-context.xml" })
public class MyTest
{
I would like to mock a value for my "defaultUrl" field. Note that I don't want to mock values for the other fields — I'd like to keep those as they are, only the "defaultUrl" field. Also note that I have no explicit "setter" methods (e.g. setDefaultUrl) in my class and I don't want to create any just for the purposes of testing.
Given this, how can I mock a value for that one field?
You can use the magic of Spring's ReflectionTestUtils.setField in order to avoid making any modifications whatsoever to your code.
The comment from Michał Stochmal provides an example:
use ReflectionTestUtils.setField(bean, "fieldName", "value"); before invoking your bean method during test.
Check out this tutorial for even more information, although you probably won't need it since the method is very easy to use
UPDATE
Since the introduction of Spring 4.2.RC1 it is now possible to set a static field without having to supply an instance of the class. See this part of the documentation and this commit.
It was now the third time I googled myself to this SO post as I always forget how to mock an #Value field. Though the accepted answer is correct, I always need some time to get the "setField" call right, so at least for myself I paste an example snippet here:
Production class:
#Value("#{myProps[‘some.default.url']}")
private String defaultUrl;
Test class:
import org.springframework.test.util.ReflectionTestUtils;
ReflectionTestUtils.setField(instanceUnderTest, "defaultUrl", "http://foo");
// Note: Don't use MyClassUnderTest.class, use the instance you are testing itself
// Note: Don't use the referenced string "#{myProps[‘some.default.url']}",
// but simply the FIELDs name ("defaultUrl")
You can use this magic Spring Test annotation :
#TestPropertySource(properties = { "my.spring.property=20" })
see
org.springframework.test.context.TestPropertySource
For example, this is the test class :
#ContextConfiguration(classes = { MyTestClass.Config.class })
#TestPropertySource(properties = { "my.spring.property=20" })
public class MyTestClass {
public static class Config {
#Bean
MyClass getMyClass() {
return new MyClass ();
}
}
#Resource
private MyClass myClass ;
#Test
public void myTest() {
...
And this is the class with the property :
#Component
public class MyClass {
#Value("${my.spring.property}")
private int mySpringProperty;
...
I'd like to suggest a related solution, which is to pass the #Value-annotated fields as parameters to the constructor, instead of using the ReflectionTestUtils class.
Instead of this:
public class Foo {
#Value("${foo}")
private String foo;
}
and
public class FooTest {
#InjectMocks
private Foo foo;
#Before
public void setUp() {
ReflectionTestUtils.setField(Foo.class, "foo", "foo");
}
#Test
public void testFoo() {
// stuff
}
}
Do this:
public class Foo {
private String foo;
public Foo(#Value("${foo}") String foo) {
this.foo = foo;
}
}
and
public class FooTest {
private Foo foo;
#Before
public void setUp() {
foo = new Foo("foo");
}
#Test
public void testFoo() {
// stuff
}
}
Benefits of this approach: 1) we can instantiate the Foo class without a dependency container (it's just a constructor), and 2) we're not coupling our test to our implementation details (reflection ties us to the field name using a string, which could cause a problem if we change the field name).
You can also mock your property configuration into your test class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({ "classpath:test-context.xml" })
public class MyTest
{
#Configuration
public static class MockConfig{
#Bean
public Properties myProps(){
Properties properties = new Properties();
properties.setProperty("default.url", "myUrl");
properties.setProperty("property.value2", "value2");
return properties;
}
}
#Value("#{myProps['default.url']}")
private String defaultUrl;
#Test
public void testValue(){
Assert.assertEquals("myUrl", defaultUrl);
}
}
I used the below code and it worked for me:
#InjectMocks
private ClassABC classABC;
#Before
public void setUp() {
ReflectionTestUtils.setField(classABC, "constantFromConfigFile", 3);
}
Reference: https://www.jeejava.com/mock-an-autowired-value-field-in-spring-with-junit-mockito/
Also note that I have no explicit "setter" methods (e.g. setDefaultUrl) in my class and I don't want to create any just for the purposes of testing.
One way to resolve this is change your class to use Constructor Injection, that can be used for testing and Spring injection. No more reflection :)
So, you can pass any String using the constructor:
class MySpringClass {
private final String defaultUrl;
private final String defaultrPassword;
public MySpringClass (
#Value("#{myProps['default.url']}") String defaultUrl,
#Value("#{myProps['default.password']}") String defaultrPassword) {
this.defaultUrl = defaultUrl;
this.defaultrPassword= defaultrPassword;
}
}
And in your test, just use it:
MySpringClass MySpringClass = new MySpringClass("anyUrl", "anyPassword");
Whenever possible, I set the field visibility as package-protected so it can be accessed from the test class. I document that using Guava's #VisibleForTesting annotation (in case the next guy wonders why it's not private). This way I don't have to rely on the string name of the field and everything stays type-safe.
I know it goes against standard encapsulation practices we were taught in school. But as soon as there is some agreement in the team to go this way, I found it the most pragmatic solution.
Another way is to use #SpringBootTest annotation properties field.
Here we override example.firstProperty property:
#SpringBootTest(properties = { "example.firstProperty=annotation" })
public class SpringBootPropertySourceResolverIntegrationTest {
#Autowired private PropertySourceResolver propertySourceResolver;
#Test
public void shouldSpringBootTestAnnotation_overridePropertyValues() {
String firstProperty = propertySourceResolver.getFirstProperty();
String secondProperty = propertySourceResolver.getSecondProperty();
Assert.assertEquals("annotation", firstProperty);
Assert.assertEquals("defaultSecond", secondProperty);
}
}
As you can see It overrides only one property. Properties not mentioned in #SpringBootTest stay untouched. Therefore, this is a great solution when we need to override only specific properties for the test.
For single property you can write it without braces:
#SpringBootTest(properties = "example.firstProperty=annotation")
Answer from: https://www.baeldung.com/spring-tests-override-properties#springBootTest
I also encourage you to whenever possible pass property as a parameter in constructor like in Dherik answer (https://stackoverflow.com/a/52955459/1673775) as it enables you to mock properties easily in unit tests.
However in integration tests you often don't create objects manually, but:
you use #Autowired
you want to modify property used in a class that is used in your integration test indirectly as it is deep dependency of some directly used class.
then this solution with #SpringBootTest might be helpful.

using spring test context to initialize data

I was wondering if it's possible to initialize test data by implementing the TestExecutionListener interface and use the beforeTestClass and afterTestClass to load/dispose data. The test data will be available in a flat file and I would like the data file location to be as part of the test class annotation
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"classpath:spring/test-dao.xml"})
#TestExecutionListeners(
{
DependencyInjectionTestExecutionListener.class,
InsertTestDataExecutionListener.class
})
#DataSetLocation("classpath:data/test-dao-dataset.xml")
public abstract class AbstractDaoTests {
public List testdata....
}
In the above pseudocode, the InsertTestDataExecutionListener will implement the TestExecutionListener interface and in the beforeClass method, get the dataset location from the annotation. I am trying to find out how I could setup the contents of the property 'testdata' using the TestContext.
public class InsertTestDataExecutionListener implements TestExecutionListener {
public void beforeTestClass(TestContext aContext) {
DataSetLocation dsLocation = aContext.getTestClass().getAnnotation(
DataSetLocation.class
);
//Load the contents of the file using the dataset location.
?? How to set the property of 'testdata' from the Abstract class
}
}
Should I be using reflection to do the work?
As I undestand it is not required to access Spring context during data load (it is just plain file in classpath). So, you may do the work without listeners:
public abstract class AbstractDaoTests {
public List testdata;
public List getTestData() {...}
public abstract String getDataLocation();
public AbstractDaoTests () {
testData = loadDataFromLocation(getTestData());
}
}
public class ConcreteTest extend AbstractDaoTests {
#Override
public String getDataLocation() {return "classpath:data/test-dao-dataset.xml";}
}
Of course you may use annotation instead of abstract method and get it from this.getClass().getAnnotation in constuctor.

Can I use inter-type declaration to add a property?

We have domain objects that extend an abstract base class to support a timestamp
abstract class TimestampedObject {
private Date timestamp;
public Date getTimestamp(){return timestamp;}
public void setTimestamp(final Date timestamp){this.timestamp = timestamp;}
}
But this clutters our hierarchy.
Could we use Spring AOP introductions or Aspectj ITDs to achieve this ?
An example right out of the AspectJ in Action book (from memory not tested) would go something like this:
public interface Timestamped {
long getTimestamp();
void setTimestamp();
public static interface Impl extends Timestamped {
public static aspect Implementation {
private long Timestamped.Impl.timestamp;
public long Timestamped.Impl.getTimestamp(){ return timestamp; }
public void Timestamped.Impl.setTimestamp(long in) { timestamp = in; }
}
}
//and then your classes would use it like this:
public class SomeClass implements Timestamped.Impl {
private void someFunc() {
setTimestamp(12);
long t = getTimestamp();
}
}
Not sure if the book had it that way or not but I usually create a separate Impl interface (as shown above) that just extends the main one so that some of my classes can implement timestamping differently without acquiring the ITD implementation. Like so :
public class SomeOtherClass implements Timestamped {
private long myOwnPreciousTimestamp;
public long getTimestamp() {
//Oh! I don't know should I give it to you?!
//I know, I will only give you a half of my timestamp
return myOwnPreciousTimestamp/2;
}
//etc.....
}
Yes, this is exactly what ITDs are for.

Resources