# Tiny calculator using dependency injection and inversion of control

I've started to learn very interesting concept of DI, IoC and related stuff.

I have decided to learn it using simple application, very tiny calculator (only basic functions: add, subtract, multiply & divide), because it's very conveniently to learn any new stuff with elementary application.

My question relates to the design workflow. Right now, I've prepared the next sources:

namespace CalculatorApp
{
public interface ICalculator
{
int Subtract(int firstValue, int secondValue);
int Multiply(int firstValue, int secondValue);
int Divide(int firstValue, int secondValue);
}

public abstract class BaseCalculator : ICalculator
{
public virtual int Add(int firstValue, int secondValue)
{
return firstValue + secondValue;
}

public virtual int Subtract(int firstValue, int secondValue)
{
return firstValue - secondValue;
}

public virtual int Multiply(int firstValue, int secondValue)
{
return firstValue * secondValue;
}

public virtual int Divide(int firstValue, int secondValue)
{
return firstValue / secondValue;
}
}

public class CalculatorAgent : BaseCalculator
{
public override int Add(int firstValue, int secondValue)
{
}

public override int Subtract(int firstValue, int secondValue)
{
return base.Subtract(firstValue, secondValue);
}

public override int Multiply(int firstValue, int secondValue)
{
return base.Multiply(firstValue, secondValue);
}

public override int Divide(int firstValue, int secondValue)
{
return base.Divide(firstValue, secondValue);
}
}
}


Tests, which is using Ninject:

using System;
using System.Diagnostics;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Ninject;
using Ninject.Modules;

namespace CalculatorApp.Tests
{
class CalculatorConfig : NinjectModule
{
{
Bind<BaseCalculator>().To<CalculatorAgent>();
}
}

class TestHelper<T> : IDisposable
{
private Random random;
private IKernel kernel;
private T agent;

public T Agent
{
get
{
return agent;
}
}

public TestHelper()
{
random = new Random();
kernel = new StandardKernel(new CalculatorConfig());
agent = kernel.Get<T>();
}

internal Tuple<int, int> GenerateValues()
{
return new Tuple<int, int>
(
item1: GenerateRandomInteger(),
item2: GenerateRandomInteger()
);
}

internal int GenerateRandomInteger()
{
return random.Next(0, Byte.MaxValue);
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
if (disposing)
{
random = null;
kernel = null;

var disposable = agent as IDisposable;

if (disposable != null)
disposable.Dispose();
}
}
}

[TestClass()]
public class CalculatorTests : IDisposable
{
private TestHelper<CalculatorAgent> helper = new TestHelper<CalculatorAgent>();

[TestMethod()]
{
// Arrange
var values = helper.GenerateValues();

// Act
var testResult = values.Item1 + values.Item2;

// Assert
}

[TestMethod()]
public void SubtractRandomValues()
{
// Arrange
var values = helper.GenerateValues();

// Act
var testResult = values.Item1 - values.Item2;
Debug.WriteLine(String.Format("Subtraction result: {0}", testResult));

// Assert
Assert.AreEqual(testResult, helper.Agent.Subtract(values.Item1, values.Item2));
}

[TestMethod()]
public void MultiplyRandomValues()
{
// Arrange
var values = helper.GenerateValues();

// Act
var testResult = values.Item1 * values.Item2;
Debug.WriteLine(String.Format("Multiplication result: {0}", testResult));

// Assert
Assert.AreEqual(testResult, helper.Agent.Multiply(values.Item1, values.Item2));
}

[TestMethod()]
public void DivideRandomValues()
{
// Arrange
var values = helper.GenerateValues();

// Act
var testResult = values.Item1 / values.Item2;
Debug.WriteLine(String.Format("Division result: {0}", testResult));

// Assert
Assert.AreEqual(testResult, helper.Agent.Divide(values.Item1, values.Item2));
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
if (disposing)
{
helper.Dispose();
}
}
}
}


If to view the code, there is a part, where I suggest to register different implementations of calculator (it may be a calc with real numbers or the calc, which counts complex numbers, etc...):

class CalculatorConfig : NinjectModule
{
{
Bind<BaseCalculator>().To<CalculatorAgent>();
// here will go other implementations
}
}


I wonder:

• Is the whole design of current app the correct one?
• Have I used AAA (Arrange-Act-Assert) concept correctly?
• Have I worked with the DI correctly?
• Does it matter, if abstract class is used instead of interface?

If you are surprised with two IDisposable implementations, which are used in tests sources, so I may comment this place of code. Previously, there weren't those manual implementations until VS has argued at me, when I've run the code analysis, which has fired warnings about the absence of them.

• Q1 - sure? I mean it is not a great example. conceptually a function calculator.Add(a,b) is not very prone to needing overloads. a more common example is some endpoint, a ResultsView or even an ICalculation.Evaluate()etc. DI is about extracting what is likely to change. dependencies. Q2 - yup. Q3 - not really. currently you seem to be using the DI container as a service locator, i am not seeing any actual injection. you should have a constructor with a dependent argument that gets injected for you. not just grab it from the kernel. Q4 - yes.you are forcing inheritance. don't. use composition – apieceoffruit Mar 23 '16 at 10:11
• Is there something I am missing ? The entire CalculatorAgent class is redundant it's simply calling the base methods you are not overriding anything. – Denis Dec 24 '16 at 23:37