I'm having a hard trying to find to correct approach to this :
My data structures :
public abstract class Flow
{
public virtual double Value { get; set; }
public virtual DateTime Time { get; set; }
}
public class InboundFlow : Flow
{
}
public class OutboundFlow : Flow
{
}
My business objects containing collections of these data structures
public abstract class Fluent
{
public virtual IList<Flow> FlowCollection { get; set; }
public virtual double InitialBaseflow { get; set; }
}
public class Affluent : Fluent
{
public new virtual IList<InboundFlow> FlowCollection { get; set; }
}
public class Effluent : Fluent
{
public new virtual IList<OutboundFlow> FlowCollection { get; set; }
}
The generic method I'm trying to use :
private static void FindInitialBaseflow<T>(ref T fluent) where T : Fluent
{
var linqFluent = fluent;
var flows = linqFluent.FlowCollection.ToList().FindAll(
flow =>
flow.Time >= SOME_DATE &&
flow.Time < SOME_OTHER_DATE);
var initialBaseflow = flows.Average(flow => flow.Value);
fluent.InitialBaseflow = Math.Round(initialBaseflow, 5);
}
My problem is that calling "linqfluent.FlowCollection" in the linq method calls for the base class Fluent's FlowCollection, which is null.
How can I force the use of the child's property instead? Thanks!
You need to make the collection within Fluent generic so that the classes that inherit from it can specify the type:
public class Fluent<T>
where T : Flow
{
public IList<T> FlowCollection { get; set; }
public double InitialBaseflow { get; set; }
}
Once you have that you don't even need sub classes of Flow, you can just make it concrete.
Your use of it would be easily modified to fit this model:
private static void FindInitialBaseflow<T>(Fluent<T> fluent)
where T : Flow
{
var linqFluent = fluent;
var flows = linqFluent.FlowCollection.Where(
flow =>
flow.Time >= SOME_DATE &&
flow.Time < SOME_OTHER_DATE);
var initialBaseflow = flows.Average(flow => flow.Value);
fluent.InitialBaseflow = Math.Round(initialBaseflow, 5);
}
Also note that since you're not setting fluent in this method, there is no need to pass it by reference. It's already a class, so it is itself a reference; mutations of the referenced object will be observed by the caller.
Generics are the wrong tool. You should using polymorphism to ensure the correct implementation is called based on the type.
For example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace ConsoleApp
{
public abstract class Flow
{
public virtual double Value { get { return new Random().Next() ; } }//these values are just for demonstration purposes
public virtual DateTime Time
{
get
{
return DateTime.MinValue.AddYears(1);
}
}
}
public class InboundFlow : Flow
{
}
public class OutboundFlow : Flow
{
}
public abstract class Fluent
{
IList<Flow> _flowCollection;
public virtual IList<Flow> FlowCollection
{
get { return _flowCollection; }
set { _flowCollection = value; }
}
private double _initialBaseflow;
public virtual double InitialBaseflow
{
get { return _initialBaseflow; }
set { _initialBaseflow = value; }
}
public Fluent()
{
FlowCollection = new List<Flow>();
}
}
public class Affluent : Fluent
{
//public new virtual IList<InboundFlow> FlowCollection { get; set; }//Keep the property polymorphic
public Affluent()
{
FlowCollection = new List<Flow>();
}
}
public class Effluent : Fluent
{
//public new virtual IList<OutboundFlow> FlowCollection { get; set; }
public Effluent()
{
FlowCollection = new List<Flow>();
}
}
class Program
{
public static DateTime SOME_DATE { get { return DateTime.MinValue; } }
public static DateTime SOME_OTHER_DATE { get { return DateTime.Now; } }
static void Main(string[] args)
{
var inbound = new InboundFlow();
var inbound2 = new InboundFlow();
var outbound = new OutboundFlow();
var a = new Affluent();
a.FlowCollection.Add(inbound);
a.FlowCollection.Add(inbound2);
FindInitialBaseflow(a);
}
private static void FindInitialBaseflow(Fluent fluent)
{
var linqFluent = fluent;
var flows = linqFluent.FlowCollection.ToList().FindAll(
flow =>
flow.Time >= SOME_DATE &&
flow.Time < SOME_OTHER_DATE);
var initialBaseflow = flows.Average(flow => flow.Value);
fluent.InitialBaseflow = Math.Round(initialBaseflow, 5);
}
}
}
Related
there is a concept about inheritance which I do not quite understand.
I have a
protected DeveloperReport DeveloperReport; // Field
Wouldn't PersonalInfoBuilder be able to access that field ?
If yes,
public PersonalInfoBuilder MyPersonalInfo => new PersonalInfoBuilder(DeveloperReport);
Why do I still have to pass the DeveloperReport(field) into PersonalInfoBuilder constructor, when I can
just modify the protected DeveloperReport field by calling new PersonalInfoBuilder(), instead of
new PersonalInfoBuilder(DeveloperReport)?
And, how the concept of "return this" return the changes made to DeveloperReport(field) back to
DeveloperReportBuilder?
Thanks !
class DeveloperReport
{
// Properties
public int Id { get; set; }
public string Name { get; set; }
public DeveloperLevel Level { get; set; }
public int WorkingHours { get; set; }
public int HourlyRate { get; set; }
// Methods
public double CalculateSalary() => WorkingHours * HourlyRate;
}
class DeveloperReportBuilder
{
protected DeveloperReport DeveloperReport;
public PersonalInfoBuilder MyPersonalInfo => new PersonalInfoBuilder(DeveloperReport);
public DeveloperReportBuilder()
{
DeveloperReport = new DeveloperReport();
}
// return developer report.
public DeveloperReport Build() => DeveloperReport;
}
class PersonalInfoBuilder : DeveloperReportBuilder
{
public PersonalInfoBuilder(DeveloperReport report)
{
DeveloperReport = report;
}
public PersonalInfoBuilder()
{
}
public PersonalInfoBuilder NameIs(string name)
{
DeveloperReport.Name = name;
return this;
}
public PersonalInfoBuilder IDis(int id)
{
DeveloperReport.Id = id;
return this;
}
}
You only have to pass the report instance if you want to have both instances of DeveloperReportBuilder and PersonalInfoBuilder have acces to the same instance of DeveloperReport.
Inheritance will not copy the instance values.
I have this code:
Class VM
{
var MyVm;
public VM(ExternalEntities externalEntities){
MyVm = externalEntities.Reflcation.VM;
}
public bool IsVmPowerOn(){
//Do something
}
}
[TestMethod]
public void TestVM()
{
private Mock<IExternalEntities> m_externalEntities = new Mock<IExternalEntities>();
private Mock<IReflection> m_reflection = new Mock<IReflection>();
private Mock<IVm> m_vm= new Mock<IVm>();
m_externalEntities.Setup(x => x.Reflaction).Return(m_reflection.object);
m_reflection.Setup(x => x.VM).Return(m_vm.Object);
var testee = new VM(externalEntity.Object)
var ans = testee.IsVmPowerOn();
Assert.IsTrue(ans);
}
The problem is that externalEntities.Reflcation is null and the test throws a NullReferenceException so it can't activate the Vm property.
The test can't pass constructor.
The following code also throws a NullReferenceException:
m_externalEntities.Setup(x => x.Reflaction.VM).Return(m_vm.object);
How do you test this kind of code?
Why do I receive null after the setup and not the mock object?
You had a lot of compilation errors and missing pieces in your code. It was not compiling as-is. That being said, I fixed it up for you. Not sure what your trying to accomplish but this works.
public interface IVm
{
IVm MyVm { get; set; }
}
public class VM : IVm
{
public IVm MyVm { get; set; }
public VM(IExternalEntities externalEntities)
{
MyVm = externalEntities.Reflaction.VM;
}
public bool IsVmPowerOn()
{
//Do something
return true;
}
}
public interface IExternalEntities
{
IReflection Reflaction { get; set; }
}
public class ExternalEntities : IExternalEntities
{
public IReflection Reflaction { get; set; }
public ExternalEntities()
{
Reflaction = new Reflection();
}
}
public interface IReflection
{
IVm VM { get; set; }
}
public class Reflection : IReflection
{
public IVm VM { get; set; }
public Reflection()
{
VM = new VM(null);
}
}
Then using that, your test would look like this.
[TestMethod]
public void TestVM()
{
Mock<IExternalEntities> m_externalEntities = new Mock<IExternalEntities>();
Mock<IReflection> m_reflection = new Mock<IReflection>();
Mock<IVm> m_vm = new Mock<IVm>();
m_externalEntities.Setup(x => x.Reflaction).Returns(m_reflection.Object);
m_reflection.Setup(x => x.VM).Returns(m_vm.Object);
var testee = new VM(m_externalEntities.Object);
var ans = testee.IsVmPowerOn();
Assert.IsTrue(ans);
}
I am receiving an exception: "object reference not set to an instance of an object".
I am trying to evaluate if Location and Manufacturing classes method ResetAllProperties() are executed.
What em I doing wrong?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;
namespace Test
{
public class Engine
{
public Engine() { }
public EngineStatus Status { get; internal set; }
public virtual EngineLocation Location { get; set; }
public virtual EngineManufacturing Manufacturing { get; set; }
}
public abstract class EngineStatus
{
protected readonly Engine engine = null;
public EngineStatus(Engine engine)
{
this.engine = engine;
}
public abstract void ResetAllProperties();
}
public class FirstEngineStatus : EngineStatus
{
public FirstEngineStatus(Engine engine) : base(engine) { }
public override void ResetAllProperties()
{
this.engine.Location.ResetAllProperties();
this.engine.Manufacturing.ResetAllProperties();
}
}
public class EngineLocation
{
public string CustomerName { get; set; }
public virtual EngineManufacturing Manufacturing { get; set; }
public virtual Engine Engine { get; set; }
public void ResetAllProperties()
{
this.CustomerName = null;
}
}
public class EngineManufacturing
{
public Nullable<DateTime> EntryDate { get; set; }
public virtual EngineLocation Location { get; set; }
public virtual Engine Engine { get; set; }
public void ResetAllProperties()
{
this.EntryDate = null;
}
}
[TestClass]
public class Test
{
[TestMethod]
public void ResetAllProperties_AssertWasCalled()
{
// Arrange
var engine = MockRepository.GenerateMock<Engine>();
var status = MockRepository.GeneratePartialMock<FirstEngineStatus>(engine);
engine.Stub(action => action.Location.ResetAllProperties());
engine.Stub(action => action.Manufacturing.ResetAllProperties());
// Act
status.ResetAllProperties();
// Assert
engine.AssertWasCalled(action => action.Location.ResetAllProperties());
engine.AssertWasCalled(action => action.Manufacturing.ResetAllProperties());
}
}
}
You are asserting the behaviour of Location and Manufacturing, so these are the objects which should be mocked. Also, when checking that something happens use Expects not Stub. Everything else should be concrete. If you make ResetAllProperties methods virtual then the following works:
[TestMethod]
public void ResetAllProperties_AssertWasCalled()
{
var location = MockRepository.GeneratePartialMock<EngineLocation>();
var manufacturing = MockRepository.GeneratePartialMock<EngineManufacturing>();
// Arrange
var engine = new Engine
{
Location = location,
Manufacturing = manufacturing
};
var status = new FirstEngineStatus(engine);
location.Expect(action => action.ResetAllProperties());
manufacturing.Expect(action => action.ResetAllProperties());
// Act
status.ResetAllProperties();
// Assert
location.VerifyAllExpectations();
manufacturing.VerifyAllExpectations();
}
However, this seems like you are testing the implementation rather than the functionality. What do you actually want to test? It looks to me like you want to test that CustomerName and EntryDate are set to null. You can test this without using any mocking at all as follows:
[TestMethod]
public void ResetAllProperties_AssertWasCalled()
{
// Arrange
var engine = new Engine
{
Location = new EngineLocation { CustomerName = "Dzenan" },
Manufacturing = new EngineManufacturing { EntryDate = DateTime.Today }
};
var status = new FirstEngineStatus(engine);
// Act
status.ResetAllProperties();
// Assert
Assert.IsNull(engine.Location.CustomerName);
Assert.IsNull(engine.Manufacturing.EntryDate);
}
I have this c# code;
case "Cafe":
source.trendItem = new TrendingLocation<ITrendingCafe>();
break;
case "Pub":
source.trendItem = new TrendingLocation<ITrendingPub>();
break;
etc
a trendItem is defined like this;
public class TrendingItem<T> where T : ITrendingItem
{
public T trendItem { get; set; }
}
Then I have this;
public List<TrendingItem<ITrendingItem>> trendItems { get; set; }
Now for each item in the above trendItems i want to get the interfaces.
I tried using;
string g = fvm.trendItems[4].trendItem.GetType().GetInterfaces()[1].Name;
and
string g = typeof(TrendingLocation<>).GetInterfaces()[0].Name;
but neither of these lists the Generic interface such as ITrendingCafe, ITrendingRestaurant etc.
Is there a way I can get the name of the generic interface name?
You want to use the Type's GetGenericArguments method.
If I understand your structure, it will be something like:
Type[] typeArguments = fvm.trendItems[4].trendItem.GetType().GetGenericArguments();
foreach (Type tParam in typeArguments)
{
// Compare the type with the interface you are looking for.
}
I take it that ITrendingCafe is an interface that implements ITrendingItem. I wrote a quick program that takes and displays all of the interfaces that T Implements:
using System;
using System.Collections.Generic;
namespace TestConsoleApplication
{
public interface ITrendingItem
{
string ItemName { get; set; }
}
public interface ITrendingCafe : ITrendingItem
{
string CafeName { get; set; }
}
public class TrendingItem<T> where T : ITrendingItem
{
public T trendItem { get; set; }
}
public class Cafe : ITrendingCafe
{
public string ItemName { get; set; }
public string CafeName { get; set; }
}
class Program
{
static void Main(string[] args)
{
var test = new List<TrendingItem<ITrendingItem>> { new TrendingItem<ITrendingItem> { trendItem = new Cafe() } };
foreach (var trendingItem in test[0].trendItem.GetType().GetInterfaces())
{
Console.Out.WriteLine(trendingItem.Name);
}
Console.ReadKey();
}
}
}
And here is the output:
As you can see, the interface is there. Just loop through and find the one you need!
I want to use AbstractValidator<T> inside base entity class.
[Serializable]
public abstract class Entity<T> where T : Entity<T>
{
public virtual Boolean Validate(AbstractValidator<T> validator)
{
return validator.Validate(this as ValidationContext<T>).IsValid;
}
// other stuff..
}
But one of my tests fails saying that Validate() method couldn't accept null as a paramter.
[Test]
public void CategoryDescriptionIsEmpty()
{
var category = new Category
{
Title = "some title",
Description = String.Empty
};
Assert.False(category.Validate(this.validator) == true);
}
[SetUp]
public void Setup()
{
this.validator = new CategoryValidator();
}
I'm using Visual Web Developer and at the moment can't install C# Developer Express to create console application to debug the error. Since that I don't know how do I debug inside the unit test. Alternatively it would be great if some explanation could be given!
Thanks!
This topic is old, but I found useful and made a little diferent:
public abstract class WithValidation<V> where V : IValidator
{
private IValidator v = Activator.CreateInstance<V>();
public bool IsValid => !(Errors.Count() > 0);
public IEnumerable<string> Errors
{
get
{
var results = v.Validate(this);
List<string> err = new List<string>();
if (!results.IsValid)
foreach (var item in results.Errors)
err.Add(item.ErrorMessage);
return err;
}
}
}
public class Client : WithValidation<ClientValidator>
{
public Guid Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
public class ClientValidator : AbstractValidator<Client>
{
public ClientValidator()
{
RuleFor(c => c.Name).NotNull();
RuleFor(c => c.Age).GreaterThan(10);
}
}
So you can use easier now like:
Client c = new Client();
var isvalid = c.IsValid;
IList<string> errors = c.Errors;
Ok!
So solution to my problem is next (at least this works as expected):
public abstract class Entity<T> where T : Entity<T>
{
public Boolean IsValid(IValidator<T> validator)
{
// var context = new ValidationContext(this);
// var instance = context.InstanceToValidate as T;
// return validator.Validate(instance).IsValid;
return validator.Validate(this as T).IsValid;
}
}
public class Rambo : Entity<Rambo>
{
public Int32 MadnessRatio { get; set; }
public Boolean CanHarmEverything { get; set; }
}
public class RamboValidator : AbstractValidator<Rambo>
{
public RamboValidator()
{
RuleFor(r => r.MadnessRatio).GreaterThan(100);
}
}
class Program
{
public static void Main(String[] args)
{
var ramboInstance = new Rambo {
MadnessRatio = 90
};
Console.WriteLine("Is Rembo still mad?");
Console.WriteLine(ramboInstance.IsValid(new RamboValidator()));
Console.ReadKey();
}
}