Are there any options to pass data from non-static TestCaseSource or ValueSource?
I want to pass some data to tests from an injected dbContext so I can't use static sources.
The following code throws an error:
"The sourceName specified on a ValueSourceAttribute must refer to a non-null static field, property or method."
[Parallelizable(ParallelScope.All)]
[FixtureLifeCycle(LifeCycle.InstancePerTestCase)]
public class MyTests
{
public MyTests()
{
}
public IEnumerable ValueSource
{
get
{
yield return new TestCaseData("test1");
yield return new TestCaseData("test2");
// yield some data from DbContext
}
}
[Test]
public void MyTest([ValueSource(nameof(ValueSource))] string name)
{
Console.WriteLine(name);
}
}
That doesn't work either.
[Parallelizable(ParallelScope.All)]
public class MyTests
{
private static List<TestCaseData> additional = new List<TestCaseData>();
[OneTimeSetUp]
public void OneTimeSetUp()
{
additional.Add(new TestCaseData("test3"));
}
public static IEnumerable<TestCaseData> TestCases
{
get
{
yield return new TestCaseData("test1");
yield return new TestCaseData("test2");
foreach (var testCase in additional)
yield return testCase;
}
}
[Test, TestCaseSource(nameof(TestCases))]
public void MyTest(string name)
{
Console.WriteLine(name);
}
}
No.
However, you can work around the problem by using the [OneTimeSetUp] attribute to populate your static test data from the database. This will perform better, anyway, since you won't need to hit the database for each test.
[Parallelizable(ParallelScope.All)]
public class MyTests
{
private static List<TestCaseData> databaseTests = new List<TestCaseData>();
[OneTimeSetUp]
public void OneTimeSetUp()
{
var dbData = // Run query...
foreach (var item in dbData)
{
databaseTests.Add(TestCaseData(item));
}
}
public static IEnumerable ValueSource
{
get
{
yield return new TestCaseData("test1");
yield return new TestCaseData("test2");
// yield some data from DbContext
foreach (var testCase in databaseTests)
yield return testCase;
}
}
[Test]
public void MyTest([ValueSource(nameof(ValueSource))] string name)
{
Console.WriteLine(name);
}
}
NOTE: It is usually not advisable to use a real database when testing. This means your tests will require a database to be present in the environment that you run them in, instead of having tests that "just work" for whoever runs them. Instead, it is preferable to mock the data that you would ordinarily retrieve from a database so you don't have this extra dependency.
Related
I am trying to write an Update Test for different products (which are classes in this case) and different time steps :
public class UpdateTest
{
private static Product ProductLastYear;
private static Product ProductTwoYearsAgo;
public UpdateTest(Product product)
{
var previousReleasedProducts = new Products();
ProductLastYear = previousReleasedProducts.GetProduct(Years.GetLastYear());
ProductTwoYearsAgo = previousReleasedProducts.GetProduct(Years.GetTwoYearsAgo());
}
Each product needs to be installed, and afterwards it is checked if the installation was successful (this is basically a pre-step before the Update). Right now, I am using two Tests for this:
[Test, Category("UpdateLastYear")), Order((int) NunitTestOrderEnum.Order.First)]
public void InstallPreviousReleasedProduct()
{
using (var controller = new BootstrapperController(ProductLastYear))
{
controller.Install();
}
var successfulInstallation = InstallationValidator.ValidateInstall(ProductLastYear);
Assert.That(successfulInstallation, Is.True);
}
[Test, Category("UpdateTwoYearsAgo"), Order((int) NunitTestOrderEnum.Order.First)]
public void InstallTwoYearsAgoProduct()
{
using (var controller = new BootstrapperController(ProductTwoYearsAgo))
{
controller.Install();
}
var successfulInstallation = InstallationValidator.ValidateInstall(ProductTwoYearsAgo);
Assert.That(successfulInstallation, Is.True);
}
Now, both tests have some code redundancy, which I would like to avoid. I was thinking about using TestCases for this, something like :
[TestCase(ProductLastYear), Category("UpdateLastYear"), Order((int) NunitTestOrderEnum.Order.First)]
[TestCase(ProductTwoYearsAgo), Category("UpdateTwoYearsAgo"), Order((int) NunitTestOrderEnum.Order.First)]
public void InstallPreProduct(Product product)
{
using (var controller = new BootstrapperController(product))
{
controller.Install();
}
var successfulInstallation = InstallationValidator.ValidateInstall(product);
Assert.That(successfulInstallation, Is.True);
}
Is something like this possible? I tried different Syntax for that approach, but it does not seem to work that easily.
You can only use compile-time constants within attributes. However your static fields are no constants.
You can use the TestCaseSource-attribute:
[TestCaseSource(nameof(ProvideTestcases))]
public void InstallPreProduct(Product product)
{
using (var controller = new BootstrapperController(product))
{
controller.Install();
}
var successfulInstallation = InstallationValidator.ValidateInstall(product);
Assert.That(successfulInstallation, Is.True);
}
public static IEnumerable<TestCaseData> ProvideTestcases()
{
yield return new TestCaseData(ProductLastYear).SetCategory("UpdateLastYear");
yield return new TestCaseData(ProductTwoYearsAgo).SetCategory("UpdateTwoYearsAgo");
}
However that assumes your static fields are already initialized, which isn't the case. So you need a static constructor for your testclass.
[TestFixture]
public UpdateTest
{
public static ProductLastYear;
public static ProductTwoYearsAgo;
static
{
ProductLastYear = ...;
ProductTwoYearsAgo = ...;
}
}
This is pretty much boilerplate for so little duplication. So it's a tradeoff if or of it not this is worth the afford.
Another opportunity is to introduce some static constant, like an enum that reflects the property to be used:
[TestCase(MyEnum.LastYear), Category("UpdateLastYear")]
[TestCase(MyEnum.TwoYearsAgo), Category("UpdateTwoYearsAgo")]
public void InstallPreProduct(MyEnum product)
{
var Product = product == MyEnum.LastYear ?
ProductLastYear :
ProductTwoYearsAgo ;
using (var controller = new BootstrapperController(product))
{
controller.Install();
}
var successfulInstallation = InstallationValidator.ValidateInstall(product);
Assert.That(successfulInstallation, Is.True);
}
An enum is a constant expression, so you can easily use it within the test-attributes.
I have several unit tests that use some static class, for example:
public static class Utility
{
private static Data data;
public static void Init(Data data)
{
this.data = data;
}
public static void Process()
{
// Some actions that changes this.data (not reference, just inner Values)
}
}
public class Data
{
public List<string> Values { get; set; }
public void Add(string value)
{
Values.Add(value);
}
}
Each unit test initializes Data instance and passes it to Utility:
[Fact]
public void UnitTest1()
{
var data = new Data();
data.Add("val1");
Utility.Init(data);
Utility.Process();
// check changed data instance
}
[Fact]
public void UnitTest2()
{
var data = new Data();
data.Add("another_val1");
data.Add("another_val2");
Utility.Init(data);
Utility.Process();
// check changed data instance
}
If I run each test separately then there is no problem - no failed tests.
But If I run tests sequentially then one of the unit tests is failed because Utility.data contains instance from previous test (for a short time) despite of Utility.Init call.
If I run tests through command line (tests performs very fast) then big part of tests is failed most likely for the same reason. How can I resolve this problem?
Because of the nature of the static utility all the tests are accessing a shared static resource which can have negative effects as already experience. I suggest making the utility class an instance class
public class Utility
{
private Data data;
public Utility(Data data) {
this.data = data;
}
public void Process() {
// Some actions that changes this.data (not reference, just inner Values)
}
}
Which an example test would look like
[Fact]
public void UnitTest1() {
//Arrrange
var data = new Data();
data.Add("val1");
var subject = new Utility(data);
//Act
subject.Process();
//Assert
// check changed data instance
}
I suspect that the initil issue was an XY problem and that the Utility is also being used as a static dependency in production, which is a code smell.
In that case abstract the static utility class
public interface IUtility {
void Process(Data data);
}
and refactor the implementation
public class Utility : IUtility {
public void Process(Data data) {
// Some actions that changes this.data (not reference, just inner Values)
}
}
Which would result in a test looking like
[Fact]
public void UnitTest1() {
//Arrrange
var data = new Data();
data.Add("val1");
var subject = new Utility();
//Act
subject.Process(data);
//Assert
// check changed data instance
}
[Fact]
public void UnitTest2() {
var data = new Data();
data.Add("another_val1");
data.Add("another_val2");
var subject = new Utility();
//Act
subject.Process(data);
//Assert
// check changed data instance
}
The IUtility would be injected into dependent classes as needed, which would make the resulting code more SOLID.
When I execute my test case, it fails for path within my machine which doesn't exist and I am getting below error:
System.IO.DirectoryNotFoundException: Could not find a part of the
path 'C:\Data1'.
Do I need some kind of fake/mock here to pass the test case or do we have other way to do this?
Class
public class DemoCls
{
public void Execute()
{
string dataFolder = #"C:\\Data1";
foreach (string X in Directory.EnumerateFiles(dataFolder, "test" + "*.xml"))
{
}
}
}
Test Case
[TestClass()]
public class DemoClsTests
{
[TestMethod()]
public void ExecuteTest()
{
var X = new DemoCls();
X.Execute();
}
}
Class should be refactored to remove tight coupling to implementation concerns that make it difficult to test.
//...Creat an abstraction that provides the desired behavior as a contract
public interface IDirectoryService {
IEnumerable<string> EnumerateFiles(string path, string searchPattern);
}
A fake/mock can be created for when testing to avoid pitfalls associated with testing IO code in isolation.
A mocking framework could have been used for stubbing the dependencies, but for this example using a simple
public class FakeDIrectoryService : IDirectoryService {
IEnumerable<string> files;
public FakeDIrectoryService(IEnumerable<string> files) {
this.files = files;
}
public IEnumerable<string> EnumerateFiles(string path, string searchPattern = null) {
return files;
}
}
Class needs to be refactored now to follow Explicit Dependencies Principle via constructor and method injection.
public class DemoCls {
IDirectoryService directory;
public DemoCls(IDirectoryService directory) {
this.directory = directory;
}
public void Execute(string dataFolder) {
foreach (var x in directory.EnumerateFiles(dataFolder, "test*.xml")) {
//...
}
}
}
Test can now be properly exercised in isolation.
[TestClass()]
public class DemoClsTests {
[TestMethod()]
public void ExecuteTest() {
//Arrange
var fakePath = "C:/temp";
var fakeFiles = new[] {
#"C:\\temp\\testfakefilename1.txt",
#"C:\\temp\\testfakefilename2.txt",
#"C:\\temp\\testfakefilename3.txt"
};
var service = new FakeDIrectoryService(fakeFiles);
var sut = new DemoCls(service);
//Act
sut.Execute(fakePath);
//Assert
//perform your assertions
}
}
Finally for production code the real implementation of the file service can wrap any source, be it disk or remote service.
For example
public class FileService : IDirectoryService {
public IEnumerable<string> EnumerateFiles(string path, string searchPattern) {
return Directory.EnumerateFiles(path, searchPattern);
}
}
This is just an example of what can be done. There is a lot of room for improvement but this should get things started.
Hardcoded paths are not good to have and I would recommend two options since the class is not static.
1st
public class DemoCls
{
public void Execute(string targetPath)
{
foreach (string X in Directory.EnumerateFiles(targetPath, "test" + "*.xml"))
{
}
}
}
This keeps things more flexible and reusable
2nd
public class DemoCls
{
private string _targetPath;
public DemoCls(string targetPath){
_targetPath = targetPath;
}
public void Execute(string targetPath)
{
foreach (string X in Directory.EnumerateFiles(targetPath, "test" + "*.xml"))
{
}
}
}
This way keeps the Execute method cleaner (less preferred)
This is my first question here and i'm not very familliar with the C# terminology, so if i get some terms or definitions mixed up i appologize in advance.
I have set up a generic EF data access layer;
public class BaseService<TObject> where TObject : class
{
private DbContext Context;
private static readonly Lazy<BaseService<TObject>> lazy = new Lazy<BaseService<TObject>>(() => new BaseService<TObject>());
public static BaseService<TObject> Instance => lazy.Value;
public BaseService()
{
Context = new evEntities();
}
public BaseService(DbContext context)
{
Context = context;
}
public ICollection<TObject> GetAll()
{
return Context.Set<TObject>().ToList();
}
public async Task<ICollection<TObject>> GetAllAsync()
{
return await Context.Set<TObject>().ToListAsync();
}
public TObject Get(int id)
{
return Context.Set<TObject>().Find(id);
}
}
Together with this;
public static class DA
{
public static DataAccess.Categories Categories => new DataAccess.Categories();
public static DataAccess.Tags Tags => new DataAccess.Tags();
public static DataAccess.Users Users => new DataAccess.Users();
}
public static class DA<T> where T : class
{
public static BaseService<T> Base => new BaseService<T>();
}
So in my Business Layer i can do this;
public class Categories
{
public Categories() { }
public ICollection<Database.Categories> GetAll()
{
return DA.Categories.GetAll().ToList();
}
public async Task<ICollection<Database.Categories>> GetAllAsync()
{
return await DA.Categories.GetAllAsync();
}
public Database.Categories Get(int id)
{
return DA.Categories.Get(id);
}
}
For clarity. My EF creates classes/entities like 'Database.Categories' and 'Database.Users' which i pass as 'TObject' to my BaseService to get a standard way of pulling data from my database for all my entities.
Now my question. In a similar way i want to create a generic Business Layer. Like;
public class BusinessLogicBase<TModel>
{
public ICollection<TDBModel> GetAll()
{
return null;
}
public async Task<ICollection<TDBModel>> GetAllAsync()
{
return await DA.Categories.GetAllAsync();
}
public TDBModel Get(int id)
{
return DA.Categories.Get(id);
}
}
I want to be able to call the DA with a TObject like Database.Categories but this has to be dynamic, based on the type passed to the BusinessLogicBase. So i want to do something like this (which doesn't work);
private ???? DetermineDatabaseModel()
{
switch(typeof(TModell))
{
case Models.Categories:
return Database.Categories;
case Models.Users:
return Database.Users;
}
}
So i can do this;
public ICollection<TDBModel> GetAll()
{
var databaseModel = DetermineDatabaseModel()
return DA<databaseModel>().GetAll();
}
I hope you understand my question and can help me.
Thnx!
Sorry for the long post, and for all you 9gaggers, here's a potato... No just kidding, this is serious.
Have you tried something like:
public class BusinessLogicBase<TDBModel> where TDBModel : class {
public ICollection<TDBModel> GetAll() {
return DA<TDBModel>.Base.GetAll();
}
}
UPDATE 1:
Maybe it would help You if you try to write it without generics first and then convert it into more general pattern using generics. There are some missteps that are easier to solve without generics.
Method public ICollection<TDBModel> GetAll() can't return ICollection<TDBModel> because type parameter TDBModel is not defined either in class signature or method signature. I makes more sense if you define it like this:
public class BusinessLogicBase<TModel>
{
public ICollection<TModel> GetAll()
{
return null;
}
}
UPDATE 2:
try this simple console app to demonstrate dynamic keyword and watch what is stored in variables categories and users.
UPDATE 3:
Based on fiddle - I've changed IBaseService<dynamic> to dynamic:
public class BL<TModel>
{
// This is what i want to make dynamic.
// how do i create a return type that i can use in DA<>..
private Type testDetermineDatabaseModel()
{
switch(typeof(TModel).Name){
case "Categories":
return typeof(Database.Categories);
case "Users":
return typeof(Database.Users);
}
return null;
}
public ICollection<TModel> testGetAll()
{
var databaseModel = testDetermineDatabaseModel();
// return DA<databaseModel>().Base.GetAll();
return new List<TModel>();
}
// NEW
// I have constructed the following.
private dynamic baseService;
public dynamic DetermineDatabaseModel()
{
switch (typeof(TModel).Name)
{
case "Categories":
return new BaseService<Database.Categories>();
case "Users":
return new BaseService<Database.Users>();
default:
return null;
}
}
private IBaseService<TDbModel> GetBase<TDbModel>() where TDbModel : class
{
return new BaseService<TDbModel>();
}
public ICollection<TModel> GetAll()
{
ICollection<TModel> returnValue = new List<TModel>();
// This works!!!
foreach (var item in GetBase<Database.Categories>().GetAll())
{
returnValue.Add((TModel)(object)item);
}
baseService = DetermineDatabaseModel();
// This doesn't!!! It's the same thing!! :(
foreach (var item in baseService.GetAll())
{
returnValue.Add((TModel)(object)item);
}
return returnValue;
}
}
But remember, this not solve the issue You are facing. That is map 2 generic types.
before I begin with my question I want to point out that I am aware that there are tons of similar questions on stack overflow. Unfortunately none of these questions helped me finding a good solution in my concrete scenario.
The Problem:
I want to write a unit test for a static factory method which contains logic. I am looking for a way to unit test this method even if it is static. If that is not possible maybe someone can point out a better design for my class under test. I also considered using IoC but couldn't see the advantage considering unit-testing.
The Code:
public class Db
{
private XmlMapping mapping;
public static Db<T> Create()
{
var mapping = XmlMapping.Create(typeOf(T).Name);
return new Db(mapping);
}
private Db(XmlMapping mapping)
{
this.mapping = mapping;
}
}
public class XmlMapping //class under test
{
public static XmlMapping Create(string filename) //method under test
{
try
{
ValidateFilename(filename);
//deserialize xml to object of type XmlMapping
var result = Deserialize(filename);
if (result.IsInValid())
throw Exception()
return result;
}
catch (Exception)
{
throw new DbException();
}
}
}
The method Create which I want to unit test is within the class XmlMapping. This method serializes a xml file and generates an object of type XmlMapping. I tried to write a stub for the serialization part. But didn't want to call my Database Factory with a Mapping class in the constructor (constructor injection).
Edit:
My database factory is generic. The generic type is used to figure out which xml file should be louded i.e.: typeOf(T) = Customer --> XmlMapping-File = Customer.xml
The Solution (Thx to Jeff!):
public class XmlMapping : IMapping //class under test
{
internal static Func<Type, IMapping> DeserializeHandler { get; set; }
static XmlMapping()
{
DeserializeHandler = DeserializeMappingFor;
}
public static IMapping Create(Type type)
{
try
{
var mapping = DeserializeHandler(type);
if (!mapping.IsValid())
throw new InvalidMappingException();
return mapping;
}
catch (Exception ex)
{
throw new DataException("Failed to load mapping configuration from xml file.", ex);
}
}
internal XmlMapping(IMapping mapping)
{
this.Query = mapping.Query;
this.Table = mapping.Table;
this.Entity = mapping.Entity;
this.PropertyFieldCollection = mapping.PropertyFieldCollection;
}
private XmlMapping() { }
}
[TestClass]
public class MappingTests //testing class
{
[TestMethod]
public void Create_ValidDeserialization_ReturnsObjectInstance()
{
XmlMapping.DeserializeHandler = MakeFakeHandlerFor(MakeMappingStub());
var result = XmlMapping.Create(typeof(ActivityDto));
Assert.IsInstanceOfType(result, typeof(XmlMapping));
}
}
I would use a fake action handler to assist in verifying the content of the call to deserialize. Let's add a Func delegate property and default that to your serialize method. Your XmlMapping class and test would like something like:
public class XmlMapping //class under test
{
static XmlMapping()
{
// Default the handler to the normal call to Deserialize
DeserializeHandler = Deserialize;
}
public static XmlMapping Create(string filename) //method under test
{
//deserialize xml to object of type XmlMapping
//preudocode:
var result = DeserializeHandler(string.Format("{0}.xml",filename));
//...
return result;
}
// Abstract indirection function to allow you to swap out Deserialize implementations
internal static Func<string, XmlMapping> DeserializeHandler { get; set; }
private static XmlMapping Deserialize(string fileName)
{
return new XmlMapping();
}
}
public class CreateTests {
public void CallingDeserializeProperly()
{
// Arrange
var called = false;
Func<string, XmlMapping> fakeHandler = (string f) =>
{
called = true; // do your test of the input and put your result here
return new XmlMapping();
};
// Act
XmlMapping.DeserializeHandler = fakeHandler;
var m = XmlMapping.Create("test");
// Assert
Assert.IsTrue(called);
}
}