Decoupling issue - improvements and alternatives - c#

I'm into learning SOLID principles - especially Inversion Of Control-DI-Decoupling, and as I'm reviewing one of my codes, I noticed that this one method (see below) gets my attention.
This code will be called by any methods that needs to read the json file, accepts string values that will be used to lookup on a json file. But as you can see(I simplified the code - excluded the exception handling for the sake of this topic), I'm not sure where to start(there are a lot of initializations or dependencies?? happening and I'm not sure where to start).
Could this method/scenario a good candidate to start with? Which do you think should I retain? and needs to be decoupled?
Thanks.
public async Task<object> ReadJsonByKey(string jsonPath, string jsonKey)
{
// First - is it okay to have an initialization at this stage?
var value = new object();
// Second - is this fine to have this in the scope of this method?
using (TextReader reader = File.OpenText(jsonPath))
{
// Third - Calling Jobject that accepts new instance of JsonTextReader
var jObject = await JObject.LoadAsync(new JsonTextReader(reader));
obj = jObject.SelectToken(jsonKey);
}
return value;
}
The reason also I asked this is because (based from the standards ) loosely-coupled stuff can be easily tested - i.e, Unit Testing
[UnitTestSuite]
[TestCase1]
// Method should only be able to accept ".json" or ".txt" file
[TestCase2]
// JsonPath file is valid file system
[TestCase3]
// Method should be able to retrieve a node value based from a specific json and key
[TestCase4]
// Json-text file is not empty

It looks like you're trying to decouple an infrastructural concern from your application code.
Assuming that's the case you need a class which is responsible for reading the data:
public interface IDataReader
{
Task<object> ReadJsonByKey(string jsonPath, string jsonKey)
}
The implementation of which would be your above code:
public class DataReader : IDataReader
{
public async Task<object> ReadJsonByKey(string jsonPath, string jsonKey)
{
// First - is it okay to have an initialization at this stage?
var value = new object();
// Second - is this fine to have this in the scope of this method?
using (TextReader reader = File.OpenText(jsonPath))
{
// Third - Calling Jobject that accepts new instance of JsonTextReader
var jObject = await JObject.LoadAsync(new JsonTextReader(reader));
obj = jObject.SelectToken(jsonKey);
}
return value;
}
}
However this class is now doing both file reading & de-serialization so you could further separate into:
public class DataReader : IDataReader
{
IDeserializer _deserializer;
public DataReader(IDeserializer deserializer)
{
_deserializer = deserializer;
}
public async Task<object> ReadJsonByKey(string jsonPath, string jsonKey)
{
var json = File.ReadAllText(jsonPath);
return _deserializer.Deserialize(json, jsonKey);
}
}
This would mean that could now unit test your IDeserializer independently of the file system dependency.
However, the main benefit should be that you can now mock the IDataReader implementation when unit testing your application code.

Make the function like:
public async Task<object> ReadJsonByKey(TextReader reader, string jsonKey)
Now the function works with any TextReader implementation, so you can pass a TextReader that reads from file or from memory or from any other data source.

The only thing that prevents you from unit-testing this properly is the File reference, which is a static. You won't be able to provide the method with a file, because it would have to physically exist. There are two ways you can go about solving this.
First, if it's possible, you could pass something else rather than a path to the method - a FileStream for example.
Second, arguably better, you would abstract the file system (I recommend using the System.IO.Abstractions and then the related TestingHelpers package) into a private field, pass the dependency via ctor injection.
private readonly IFileSystem fileSystem;
public MyClass(IFileSystem fileSystem)
{
this.fileSystem = fileSystem;
}
And then in your method you'd use
fileSystem.File.OpenText(jsonPath);
This should allow you to unit-test this method with ease, by passing a MockFileSystem and creating a json file in-memory for the method to read. And unit-testability is actually a good indicator that your method is maintainable and has a well defined purpose - if you can test it easily with a not-so-complicated unit test, then it's probably good. If you can't, then it's definitely bad.

Related

In Azure API for VM, is there a way to define many existing data disks with one method?

I have a block of fluent C# code:
If I knew how many disks existed the syntax would be:
var tempVM = await azure.VirtualMachines.Define(targetVMName)
.WithRegion(vm.Region)
.WithExistingResourceGroup(targetResourceGroupName)
.WithNewPrimaryNetworkInterface(nicDefinitions[0])
.WithSpecializedOSDisk(disks[0], disks[0].OSType.Value)
.WithSize(vm.Size)
.WithTags(tags)
.WithExistingDataDisk(d[0]) <<<<<<<
.WithExistingDataDisk(d[1]) <<<<<<<
.WithExistingDataDisk(d[2]) <<<<<<<
.WithExistingDataDisk(d[3]) <<<<<<<
.CreateAsync();
I may have 0 or more datadisks to add. Is there a fluent syntax to support 0 or more disks ?
Assuming this is using extension method on an interface named IWithManagedCreate, you have this method:
public static IWithManagedCreate WithExistingDataDisk(this IWithManagedCreate vm, IDisk disk)
{
// ...
return vm;
}
You could simply add an extension method of your own with a params IDisk[] overload:
public static IWithManagedCreate WithExistingDataDisks(this IWithManagedCreate vm, params IDisk[] disks)
{
foreach (var disk in disks)
{
vm = vm.WithExistingDataDisk(disk);
}
return vm;
}
And call it like that:
.WithTags(tags)
.WithExistingDataDisks(d) // passing the array containing 0 or more disks
.CreateAsync();
So, to answer the question, no, fluent syntax is nothing special, just a chain of method calls. When you chain method calls (by letting each method return something that you can call more methods on), you can't make them conditional; you can make a method however do nothing as demonstrated above. When you call it with an empty array, nothing happens.
The WithExistingDataDisk is declared in the IWithManagedDataDisk interface.
This interface doesn't provide any method to add many existing IDisk in one call.
Anyway, you can implement it as an extension method like this :
public static class WithManagedDataDiskExtensions
{
// allow to manually specify many disks to add
public static IWithManagedDataDisk WithExistingDataDisks(this IWithManagedDataDisk self, params IDisk[] disks)
{
return self.WithExistingDataDisks((IEnumerable<IDisk>) disks);
}
// allow to add an enumerable of many disks
public static IWithManagedDataDisk WithExistingDataDisks(this IWithManagedDataDisk self, IEnumerable<IDisk> disks)
{
foreach (var disk in disks)
self = self.WithExistingDataDisk(disk);
return self;
}
}
and use it like that:
var tempVM = await azure.VirtualMachines.Define(targetVMName)
.WithRegion(vm.Region)
.WithExistingResourceGroup(targetResourceGroupName)
.WithNewPrimaryNetworkInterface(nicDefinitions[0])
.WithSpecializedOSDisk(disks[0], disks[0].OSType.Value)
.WithSize(vm.Size)
.WithTags(tags)
.WithExistingDataDisks(d[0], d[1], d[2], d[3])
//.WithExistingDataDisks(d)
.CreateAsync();
Often in fluent API's you can use an assignment in a loop, like this:
var expTempVM = azure.VirtualMachines.Define(targetVMName)
.WithRegion(vm.Region)
.WithExistingResourceGroup(targetResourceGroupName)
.WithNewPrimaryNetworkInterface(nicDefinitions[0])
.WithSpecializedOSDisk(disks[0], disks[0].OSType.Value)
.WithSize(vm.Size)
.WithTags(tags);
foreach (var d in disks)
{
expTempVM = expTempVM.WithExistingDataDisk(d);
}
var tempVM = await expTempVM.CreateAsync();
As the basic design of a fluent API is that each method returns the same type that it operates on.
And if you can do that, you can also define your own extension method, .WithExistingDataDisks or similar.

"Simulate" command line argument in unit-tests

I have some functionality, which depends on command line arguments, and different arguments should lead to different results.
I can't directly "simulate" this arguments, since there are some sort of chain dependencies - I need to unit-test some xaml control, which depends on view-model, which depends on certain additional class, which fetches command line arguments using Environment.GetCommandLineArgs, and I can't directly impact on this last class to set arguments manually instead of using GetCommandLineArgs.
So, I'd like to know, is there any way to make Environment.GetCommandLineArgs return value I want it to return, for certain unit-test.
You need to abstract Environment.GetCommandLineArgs or what ever is eventually calling it behind something you can mock
public interface ICommandLineInterface {
string[] GetCommandLineArgs();
}
Which can eventually be implemented in a concrete class like
public class CommandInterface : ICommandLineInterface {
public string[] GetCommandLineArgs() {
return Environment.GetCommandLineArgs();
}
}
And can be Tested using Moq and FluentAssertions
[TestMethod]
public void Test_Should_Simulate_Command_Line_Argument() {
// Arrange
string[] expectedArgs = new[] { "Hello", "World", "Fake", "Args" };
var mockedCLI = new Mock<ICommandLineInterface>();
mockedCLI.Setup(m => m.GetCommandLineArgs()).Returns(expectedArgs);
var target = mockedCLI.Object;
// Act
var args = target.GetCommandLineArgs();
// Assert
args.Should().NotBeNull();
args.Should().ContainInOrder(expectedArgs);
}
Since you are dealing with environment variables, why don't we wrap the outside dependencies into one EnvironmentHelper class, then inject the dependencies?
Here is my suggestion:
public class EnvironmentHelper
{
Func<string[]> getEnvironmentCommandLineArgs;
// other dependency injections can be placed here
public EnvironmentHelper(Func<string[]> getEnvironmentCommandLineArgs)
{
this.getEnvironmentCommandLineArgs = getEnvironmentCommandLineArgs;
}
public string[] GetEnvironmentCommandLineArgs()
{
return getEnvironmentCommandLineArgs();
}
}
Here is the Mock method:
public static string[] GetFakeEnvironmentCommandLineArgs()
{
return new string[] { "arg1", "arg2" };
}
In your source code:
EnvironmentHelper envHelper = new EnvironmentHelper(Environment.GetCommandLineArgs);
string[] myArgs = envHelper.GetEnvironmentCommandLineArgs();
In your unit test code:
EnvironmentHelper envHelper = new EnvironmentHelper(GetFakeEnvironmentCommandLineArgs);
string[] myArgs = envHelper.GetEnvironmentCommandLineArgs();
You can do it much more easier with Typemock Isolator.
It allows to mock not only interfaces, so. Take a look:
[TestMethod, Isolated]
public void TestFakeArgs()
{
//Arrange
Isolate.WhenCalled(() => Environment.GetCommandLineArgs()).WillReturn(new[] { "Your", "Fake", "Args" });
//Act
string[] args = Environment.GetCommandLineArgs();
//Assert
Assert.AreEqual("Your", args[0]);
Assert.AreEqual("Fake", args[0]);
Assert.AreEqual("Args", args[0]);
}
Mocking Environment.GetCommandLineArgs() took only one line:
Isolate.WhenCalled(() => Environment.GetCommandLineArgs()).WillReturn(new[] { "Your", "Fake", "Args" });
And you don't need to create new Interfaces and to change production code.
Hope it helps!
If you want something unit-testable it should have its dependencies on a abstraction that is at least as strict as its implementation.
Usually you'd get the dependencies through your constructor of your class or a property method. Constructor is preferred, generally, because now a consumer of your class knows at compile-time what dependencies are needed.
public void int Main(string[] args)
{
// Validate the args are valid (not shown).
var config = new AppConfig();
config.Value1 = args[0];
config.Value2 = int.Parse(args[1]);
// etc....
}
public class MyService()
{
private AppConfig _config;
public MyService(AppConfig config)
{
this._config = config;
}
}
I normally don't put a config object behind an interface because it only has data - which is serializable. As long as it has no methods, then I shouldn't need to replace it with a subclass with override-d behavior. Also I can just new it up directly in my tests.
Also, I've never ran into a situation when I wanted to depend on an abstraction of the command line arguments themselves to a service - why does it need to know it's behind a command-line? The closest I've gotten is use PowerArgs for easy parsing, but I'll consume that right in Main. What I normally do is something like maybe read in the port number for a web server on the command-line arguments (I let the user of the app choose so that I can run multiple copies of my web server on the same machine - maybe different versions or so I can run automated tests while I'm debugging and not conflict ports), parse them directly in my Main class. Then in my web server I depend on the parsed command-line arguments, in this case an int. That way the fact that the configuration is coming from a command-line is irrelevant - I can move it to an App.config file later (which is also basically bound to the lifecycle of the process) if I prefer - then I can extract common configuration to configSource files.
Instead of depending on an abstraction for command-line in general (which each service consuming would have to re-parse if you kept it pure), I usually abstract the command-line and App.config dependencies to a strongly-typed object - maybe an app-level config class and a test-level config class and introduce multiple configuration objects as needed - (the app wouldn't necessarily care about this, while the E2E test infrastructure would need this in a separate part of the App.config: where do I grab the client static files from, where do I grab the build scripts in a test or developer environment to auto-generate/auto-update an index.html file, etc.).

Is Moq incompatible with PrivateObject?

I'm trying to test a private method on a mocked object. Please, calm down, I know you're getting your pitchforks out.
I'm well aware everything about to say can be answered by yelling REFACTOR at me. I just need a straight answer. Someone look me in the eyes and tell me this can't be done. It's an ungoogleable problem, so I just need to hear it.
Here's what I'm dealing with.
public class SecretManager
{
protected virtual string AwfulString { get { return "AWFUL, AWFUL THING"; }
public SecretManager()
{
//do something awful that should be done using injection
}
private string RevealSecretMessage()
{
return "don't forget to drink your ovaltine";
}
}
Here's me trying to test it.
var mgr = new Mock<SecretManager>();
mgr.Protected().SetupGet<string>("AwfulThing").Returns("");
var privateObj = new PrivateObject(mgr.Object);
string secretmsg = privateObj.Invoke("RevealSecretMessage");
Assert.IsTrue(secretmsg.Contains("ovaltine"));
and the exception:
System.MissingMethodException: Method 'Castle.Proxies.SecretManagerProxy.RevealSecretMessage' not found
Is what I'm trying to do, mad as it is, possible? Or is this simply too much hubris for a unit test to bear?
You're trying to call a method on the proxy that Castle created. The proxy won't have access to the private method on the class that it inherits from because, well, the method is private. Remember that Castle.Proxies.SecretManagerProxy is actually a subclass of SecretManager.
Do you really need a mock of SecretManager? I realize your code is a slimmed down abstract of the real code, but it seems the only thing you're doing with the mock is setting up a return for a property that isn't used by the method you're trying to test anyway.
var privateObj = new PrivateObject(mgr.Object, new PrivateType(typeof(SecretManager)));
string secretmsg = privateObj.Invoke("RevealSecretMessage");
It will work by specifying PrivateType for the PrivateObject.
Your code should be following for what you are trying to test. You don't need to mock the SecretManager and SetGet "AwfulThing" as you are not using it.
var privateObj = new PrivateObject(new SecretManager());
string secretmsg = (string)privateObj.Invoke("RevealSecretMessage", new object[] { });
Assert.IsTrue(secretmsg.Contains("ovaltine"));
But ideally you shouldn't be testing Private methods. See below article for the explanation:
http://lassekoskela.com/thoughts/24/test-everything-but-not-private-methods/

Difference between clsObject.Method() and new Class().Method()?

Suppose i am having a class
Class ABC
{
public string Method1()
{
return "a";
}
public string Method2()
{
return "b";
}
public string Method3()
{
return "c";
}
}
and Now i am calling this methods in two ways like :
ABC obj=new ABC();
Response.Write(obj.Method1());
Response.Write(obj.Method2());
Another way
Response.Write(new ABC().Method1());
Response.Write(new ABC().Method2());
The output will be same for above two method .
Can some please help me understanding the difference between obj.Method1() and new ABC().Method1()
Thanks in Advance..
obj and new ABC() are separate instances. In your example the output is the same because there is no instance-level data to show.
Try this to see the difference:
Class ABC
{
public string Name = "default";
public string Method1()
{
return "a";
}
}
then use the code below to show the difference with instance-level data:
ABC obj=new ABC();
obj.Name = "NewObject";
Response.Write(obj.Method1());
Response.Write(obj.Name);
Response.Write(new ABC().Method1());
Response.Write(new ABC().Name);
What #d-stanley is trying to say is that you allocate memory on creation that is is very valuable resource.
And the more complete answer is this: Classes created with some logic in mind. Although is perfectly workable Response.Write(new ABC().Method1()); but this is very short function and not as much useless... When you design class you implemented some logic boundary functionality and properties. For example FileStream has a inner property of Stream and make it accessible via various properties and you could set it in overloaded Open() method and destroy it in Dispose() method. And for example another class BinaryReader implements Stream also but threat it differently. From your logic you could implement all functions on single class - some MotherOfAllFunctions class the implements all the functions of FileStream and BinaryReader - but it's not a way of doing it.
Another point: In most of the cases some (or huge) ammount of memory is taken to initialize some internal logic of the class - for example SqlConnection class. Then you call Open() or any other method to call a database - there's some very powerful mechanics is thrown kick-in to support state machine initialization, managed-to-unmanagment calls and a lot of code could be executed.
Actually what you doing in any new SomeCLass().SomeMethod<int>(ref AnotherObject) is:
Response.Write(
var tmpABC = new ABC(); // Constructor call . Executed always (may throw)
string result = tmpABC.Method1(); // Or whatever could be casted to `string`
tmpABC.Dispose(); // GC will kick-in and try to free memory
return result;
);
As you see - this is the same code as if you have written it in this way. So what happens here is a lot of memory allocations and almost immediately all this valuable memory is thrown away. It makes more sense to initialize ABC() class and all it functionality power once and then use it everywhere so minimize memory over allocation. For example - it doesn't make any sense to open SqlConnection function in every function call in your DAL class the then immediately close it - better declare local variable and keep it alive - some fully initialized classes live as long as application thread process exist. So in case of this code style:
public class Program
{
private static FileStream streamToLogFile = new FileStream(...);
public int Main(string [] args)
{
new Run(new Form1(streamToLogFile));
}
}
In this logic - there's no need to keep class Form1 and I created it inline but all the functions the need to access FileStream object (valuable resource !) will access the same instance that been initialized only once.

Change object type at runtime maintaining functionality

Long story short
Say I have the following code:
// a class like this
class FirstObject {
public Object OneProperty {
get;
set;
}
// (other properties)
public Object OneMethod() {
// logic
}
}
// and another class with properties and methods names
// which are similar or exact the same if needed
class SecondObject {
public Object OneProperty {
get;
set;
}
// (other properties)
public Object OneMethod(String canHaveParameters) {
// logic
}
}
// the consuming code would be something like this
public static void main(String[] args) {
FirstObject myObject=new FirstObject();
// Use its properties and methods
Console.WriteLine("FirstObject.OneProperty value: "+myObject.OneProperty);
Console.WriteLine("FirstObject.OneMethod returned value: "+myObject.OneMethod());
// Now, for some reason, continue to use the
// same object but with another type
// -----> CHANGE FirstObject to SecondObject HERE <-----
// Continue to use properties and methods but
// this time calls were being made to SecondObject properties and Methods
Console.WriteLine("SecondObject.OneProperty value: "+myObject.OneProperty);
Console.WriteLine("SecondObject.OneMethod returned value: "+myObject.OneMethod(oneParameter));
}
Is it possible to change FirstObject type to SecondObject and continue to use it's properties and methods?
I've total control over FirstObject, but SecondObject is sealed and totally out of my scope!
May I achieve this through reflection? How? What do you think of the work that it might take to do it? Obviously both class can be a LOT more complex than the example above.
Both class can have templates like FirstObject<T> and SecondObject<T> which is intimidating me to use reflection for such a task!
Problem in reality
I've tried to state my problem the easier way for the sake of simplicity and to try to extract some knowledge to solve it but, by looking to the answers, it seems obvious to me that, to help me, you need to understand my real problem because changing object type is only the tip of the iceberg.
I'm developing a Workflow Definition API. The main objective is to have a API able to be reusable on top of any engine I might want to use(CLR through WF4, NetBPM, etc.).
By now I'm writing the middle layer to translate that API to WF4 to run workflows through the CLR.
What I've already accomplished
The API concept, at this stage, is somehow similar to WF4 with ActivityStates with In/Out Arguments and Data(Variables) running through the ActivityStates using their arguments.
Very simplified API in pseudo-code:
class Argument {
object Value;
}
class Data {
String Name;
Type ValueType;
object Value;
}
class ActivityState {
String DescriptiveName;
}
class MyIf: ActivityState {
InArgument Condition;
ActivityState Then;
ActivityState Else;
}
class MySequence: ActivityState {
Collection<Data> Data;
Collection<ActivityState> Activities;
}
My initial approach to translate this to WF4 was too run through the ActivitiesStates graph and do a somehow direct assignment of properties, using reflection where needed.
Again simplified pseudo-code, something like:
new Activities.If() {
DisplayName=myIf.DescriptiveName,
Condition=TranslateArgumentTo_WF4_Argument(myIf.Condition),
Then=TranslateActivityStateTo_WF4_Activity(myIf.Then),
Else=TranslateActivityStateTo_WF4_Activity(myIf.Else)
}
new Activities.Sequence() {
DisplayName=mySequence.DescriptiveName,
Variables=TranslateDataTo_WF4_Variables(mySequence.Variables),
Activities=TranslateActivitiesStatesTo_WF4_Activities(mySequence.Activities)
}
At the end of the translation I would have an executable System.Activities.Activity object. I've already accomplished this easily.
The big issue
A big issue with this approach appeared when I began the Data object to System.Activities.Variable translation. The problem is WF4 separates the workflow execution from the context. Because of that both Arguments and Variables are LocationReferences that must be accessed through var.Get(context) function for the engine to know where they are at runtime.
Something like this is easily accomplished using WF4:
Variable<string> var1=new Variable<string>("varname1", "string value");
Variable<int> var2=new Variable<int>("varname2", 123);
return new Sequence {
Name="Sequence Activity",
Variables=new Collection<Variable> { var1, var2 },
Activities=new Collection<Activity>(){
new Write() {
Name="WriteActivity1",
Text=new InArgument<string>(
context =>
String.Format("String value: {0}", var1.Get(context)))
},
new Write() {
//Name = "WriteActivity2",
Text=new InArgument<string>(
context =>
String.Format("Int value: {0}", var2.Get(context)))
}
}
};
but if I want to represent the same workflow through my API:
Data<string> var1=new Data<string>("varname1", "string value");
Data<int> var2=new Data<int>("varname2", 123);
return new Sequence() {
DescriptiveName="Sequence Activity",
Data=new Collection<Data> { var1, var2 },
Activities=new Collection<ActivityState>(){
new Write() {
DescriptiveName="WriteActivity1",
Text="String value: "+var1 // <-- BIG PROBLEM !!
},
new Write() {
DescriptiveName="WriteActivity2",
Text="Int value: "+Convert.ToInt32(var2) // ANOTHER BIG PROBLEM !!
}
}
};
I end up with a BIG PROBLEM when using Data objects as Variables. I really don't know how to allow the developer, using my API, to use Data objects wherever who wants(just like in WF4) and later translate that Data to System.Activities.Variable.
Solutions come to mind
If you now understand my problem, the FirstObject and SecondObject are the Data and System.Activities.Variable respectively. Like I said translate Data to Variable is just the tip of the iceberg because I might use Data.Get() in my code and don't know how to translate it to Variable.Get(context) while doing the translation.
Solutions that I've tried or thought of:
Solution 1
Instead of a direct translation of properties I would develop NativeActivites for each flow-control activity(If, Sequence, Switch, ...) and make use of CacheMetadata() function to specify Arguments and Variables. The problem remains because they are both accessed through var.Get(context).
Solution 2
Give my Data class its own Get() function. It would be only an abstract method, without logic inside that it would, somehow, translate to Get() function of System.Activities.Variable. Is this even possible using C#? Guess not! Another problem is that a Variable.Get() has one parameter.
Solution 3
The worst solution that I thought of was CIL-manipulation. Try to replace the code where Data/Argument is used with Variable/Argument code. This smells like a nightmare to me. I know next to nothing about System.reflection.Emit and even if I learn it my guess is that it would take ages ... and might not even be possible to do it.
Sorry if I ended up introducing a bigger problem but I'm really stuck here and desperately needing a tip/path to go on.
This is called "duck typing" (if it looks like a duck and quacks like a duck you can call methods on it as though it really were a duck). Declare myObject as dynamic instead of as a specific type and you should then be good to go.
EDIT: to be clear, this requires .NET 4.0
dynamic myObject = new FirstObject();
// do stuff
myObject = new SecondObject();
// do stuff again
Reflection isn't necessarily the right task for this. If SecondObject is out of your control, your best option is likely to just make an extension method that instantiates a new copy of it and copies across the data, property by property.
You could use reflection for the copying process, and work that way, but that is really a separate issue.

Categories

Resources