How to mock class members in C#? - c#

I'm trying to use FakeItEasy to mock an object that is a member of a C# class I'm creating.
The FakeItEasy documentation indicates that you fake an object in a way similar to this:
private static var m_physics = A.Fake<IPhysics>();
That is, using the "var" keyword.
However, in this case the C# compiler doesn't like the fact that var is being used in a non-local context. I get this error:
The contextual keyword 'var' may only appear within a local variable declaration
Can't I mock an object that's not local?

I think you're missing the point of mocks/stubs. Mocks and stubs are used for testing when you don't want the subject under test to pass or fail depending on other components that it depends on. So what you do is swap explicit implementations of these out for mocks/stubs of these dependencies that you can completely control within the test.
class Foo {
public Foo(IBar bar) { }
public object M() { // do something with IBar }
}
Here Foo has a dependency on IBar. We want to test Foo.M. We don't want the test to pass or fail based on whether or not the concrete implementation that we give to Foo of IBar is working or not.
[Fact]
public void MDoesWhatItIsSupposeToDo() {
var foo = new Foo(new Bar());
object expected = // expected result
Assert.Equal(expected, foo.M());
}
If Bar is broken this test could fail even though Foo might be coded perfectly correctly. So you sub in a mock/stub to preven this
[Fact]
public void MDoesWhatItIsSupposeToDo() {
var bar = A.Fake<IBar>();
// set up bar to do what is expected of IBars
var foo = new Foo(bar);
object expected = // expected result
Assert.Equal(expected, foo.M());
}
Now this test only passes or fails if Foo is coded correctly or not, independently of whether or not your concrete implementations of IBar are correct.
This is the point of mocks.
So all of this is to say, you are not using mocks properly.
Can't I mock an object that's not local?
You can, but not in the way that you are doing. First, fields can't be implicitly typed. Secondly, you don't mock the field explicitly like you've done. Instead you do it like this:
class Whatever {
private IPhysics m_physics;
public Whatever(IPhsyics physics) { this.m_physics = physics; }
}
Then:
var physics = A.Fake<IPhysics>();
var whatever = new Whatever(physics);

You can only use the 'var' keyword in a local context like a function block. You cannot declare a class member as a 'var'.

Related

How to Setup a readonly property with Moq?

I am trying to unit test using Moq. Here is the example code:
public class ConcreteClass
{
private readonly FirstPropery firstProperty;
private readonly SecondProperty secondProperty;
public ConcreteClass(firstProperty, secondProperty)
{
this.firstProperty = firstProperty;
this.secondProperty = secondProperty;
}
}
[TestMethod]
var concreteClassMock = new Mock<ConcreteClass>() { CallBase = true };
In my test method, I want to set firstProperty to reference a real object FirstProperty object (created by a factory), and later use it to test another object's behavior. Is there any way to achieve that?
Usually, you wouldn’t mock private members since you are only mocking the public interface of something. A mock is thus completely independent of implementation details.
That being said, you can pass constructor arguments to the Mock constructor that will then be passed on to the target’s constructor:
new Mock<ConcreteClass>(firstProperty, secondProperty) {CallBase = true};
However, if your goal is to actually test the ConcreteClass, you should not create a mock of it. You should test the actual object. So mock its dependencies and pass those if necessary, but keep the object you want to test actually real. Otherwise, you might introduce and test behavior that comes from the mock instead of the object you are testing:
var firstMock = new Mock<FirstProperty>();
var secondMock = new Mock<FirstProperty>();
var obj = new ConcreteClass(firstMock.Object, secondMock.Object);
obj.DoSomething();
// assert stuff
A few remarks:
1- It could be easily achieve with an interface and a get method like this:
public interface IConcreteClass
{
FirstProperty FirstProperty { get; }
}
[Test]
public void TestCase()
{
var yourFirstPropertyImplementation = new FirstProperty();
var concreteClassMock = new Mock<IConcreteClass>();
concreteClassMock.Setup(o => o.FirstProperty).Returns(yourFirstPropertyImplementation);
}
2- Depending of your scenario, do you really need a Moq, why not just use the true implementation and use moq only at boundaries?
3- You should clarify what you want to test? If it's concrete class? or the properties? or some other classes? The test case I propose in 1 is valid only to test the interaction of concrete class with some other classes.

Moq is making method call and returning real data, and not the return data in Setup

I am trying to return a statically declared array of NWatchNativeNode[], but Moq seems to actually be calling the real method that goes to the gets the real system data. Is the Setup in the below incorrect?
I want to make sure that when
GetNodesInCriticalCondition() is called, criticalNodes1 is returned.
Unit Test Code
var criticalNodes1 = new NWatchNativeNode[]
{
factory.CreateNativeNode(NWatchNodeType.NetworkSwitch,
"MySwitch",
"MyAlias",
12345
),
factory.CreateNativeNode(NWatchNodeType.NetworkSwitch,
"MySwitch2",
"MyAlias2",
54321
),
};
var mock = new Mock<NWatchCasModelStatusScheduleEntry>(_application);
mock.Setup(x => x.GetNodesInCriticalCondition()).Returns(criticalNodes1);
var nodes = mock.Object.GetNodesInCriticalCondition();
Assert.AreEqual(2, nodes.Length); // This should return true
The most likely reason that the Mock returns the real system data is that your method GetNodesInCriticalCondition() is not declared virtual.
In order for Moq to be able to setup the method calls, these methods have to be virtual, otherwise it cannot overwrite them and hence cannot intercept them, which results in the original method being called.
Edit:
If your method is internal, you have to give access to it to your Unit Test project and to Moq.
You can do this by adding
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] and
[assembly: InternalsVisibleTo("TestProjectNameSpace")]
to the AssemblyInfo.cs file of the project you are creating mocks for.
As per your request, here is a quick example of how to test with Moq.
Let us make some classes and interfaces to test to start with.
public interface IFoo
{
IEnumerable<int> GetFoos();
}
public class Foo : IFoo
{
public IEnumerable<int> GetFoos()
{
return Enumerable.Range(1, 10);
}
}
public class Bar
{
private readonly IFoo foo;
public Bar(IFoo foo)
{
this.foo = foo;
}
public IEnumerable<int> SquareFoos()
{
foreach(var item in foo.GetFoos())
{
yield return item * item;
}
}
}
Now, Bar has a dependency on the IFoo interface. Now we want to test the functionality of SquareFoos on the Bar class. This is our subject under test. What we want to mock is the IFoo interface passed to the constructor of Bar. This gives us the following unit test setup.
// Arrange
var mock = new Mock<IFoo>();
mock.Setup(m => m.GetFoos()).Returns(Enumerable.Range(1, 2));
var sut = new Bar(mock.Object);
// Act
var results = sut.SquareFoos().ToList();
// Assert
Assert.AreEqual(2, results.Count);
In this case we mock out what GetFoos returns to allow us to test our Bar class.

How can I add an Expression<Action<T>> as an interception to a faked object?

Is there an alternative way to intercept method calls in FakeItEasy if the method and arguments are already represented as an Expression<Action<T>>?
Normally I would simply use
IFoo foo = A.Fake<IFoo>();
A.CallTo(() => foo.SomeMethod("SomeString", A<Exception>.Ignored)).Invokes( ... );
But in my current situation I have a fake IFoo and an Expression<Action<IFoo>> and am trying to marry the two together.
This is actually existing Moq code that I'm re-writing for FakeIEasy but I'm not sure whether it's possible. The Moq version of this is
private void ExampleMoqMethod(Expression<Action<IFoo>> setupAction)
{
Mock<IFoo> Mock = new Mock<IFoo>();
Mock.Setup(setupAction).Callback( ... );
}
I tried the obvious (below) but got a "The specified object is not recognized as a fake object" error (I suspect because the fake object is not being referred to at all!)
private void ExampleFIEMethod(Expression<Action<IFoo>> callSpecification)
{
IFoo foo = A.Fake<IFoo>();
A.CallTo(callSpecification).Invokes( ... );
}
I would hazard a guess that this is possible by implementing IFakeObjectCallRule and using Fake.GetFakeManager(foo).AddRuleFirst(customRule) but I was wondering if there was a more straightforward way doing this?

Unit testing highly coupled code in .net; reflection to inject mocks?

Let's say I have a bunch of classes that look something like...
class Foo{
private Bar highlyCoupled = new highlyCoupled();
public bool DoTheThing(){
return highlyCoupled.doesTheThing();
}
}
Is it possible to use reflection to open up foo and inject (duck-punch may be a more correct term) some sort of mockHighlyCoupled in the place of highlyCoupled?
What about in this situation...
class DoubleFoo : Foo{
public bool DoTheOtherThing(){
return DoTheThing();
}
}
Can the inherited highlyCoupled have a mock inserted in it's place?
Refactoring the code so as to not require reflection isn't possible, unfortunately.
Since you can't refactor using a mocking framework could make this a bit easier for you. For Example:
TypeMock:
var fakeType = Isolate.Fake.Instance<SomeType>();
ObjectState.SetField(fakeType, "_somePrivateField", myValue);
Moq:
var fakeType = new Mock<SomeType>()
fakeType.Protected().Setup<SomeType>("_somePrivateField").Returns(myValue);
To be honest I haven't actually tried this out with Moq but I think it will do what you need.
You can indeed use reflection and a mocked type, but that type has to inherit from the original type (FieldInfo.SetValue will fail otherwise).
void Main()
{
var bar = new Bar();
var type = typeof(Bar);
// Get the type and fields of FieldInfoClass.
var fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
fields[0].SetValue(bar, new FooMock()); // you can use new Foo() here too.
bar.Print();
}
class Foo {
public int i = 0;
}
class FooMock : Foo {
}
class Bar {
private Foo foo = new Foo();
public void Print() {
Console.WriteLine(i);
}
}
If you can't refactor at all (make highlyCoupled protected), then you're stuck using reflection. That will let you set the value of highlyCoupled without modification.
I generally agree with Rob; if you can't refactor this in order to make the dependency more loosely coupled (at least allow a derived class like a test proxy to override its default value), then reflection to set the value despite its visibility is pretty much the only way you can go.
The absolute least you could do is make the dependency protected. If this is possible now or at any point in the future, do it:
class Foo{
protected Bar highlyCoupled = new highlyCoupled();
public bool DoTheThing(){
return highlyCoupled.doesTheThing();
}
}
...
//in your test suite
class FooTestProxy:Foo
{
public FooTestProxy(Bar testMock)
{
highlyCoupled = testMock;
}
}
//now when testing, instantiate your test proxy and pass it the mocked object

AutoMoqer: Passing parameters into constructors

When I'm in need to mock some class that goes like this:
public class Dummy
{
private readonly int _someInt;
private readonly int _someOtherInt;
private readonly IFoo _foo;
public Dummy(int someInt,int someOtherInt, IFoo foo)
{
_someInt = someInt;
_someOtherInt = someOtherInt;
_foo = foo;
}
}
I use Moq to do something like this:
[Test]
public void ShouldCreateADummyInstance()
{
var someInt = 1;
var someOtherInt = 2;
var mockFoo = new Mock<IFoo>();
var dummy = new Dummy(someInt, someOtherInt, mockFoo.Object);
//And so on...
}
But when I use AutoMoq I can't specify a different int for each dependency (I mean someInt and someOtherInt) into my constructor because AutoMoqer.SetInstace(instanceIWantToUse) sets the same specified instance each time that has to supply that dependecy.
Do you know how can I specify a different int for someInt and someOtherInt in order to keep using AutoMoqer in my tests ?
Thanks, hope you can help me out!
Full disclosure: I've never used AutoMoq (though I did just sign up to follow it on GitHub since it looks intriguing and I like things that cut down on boilerplate).
That said, it looks like the AutoMoq tool was designed for a different use case than yours. It appears that he uses it to "future proof" against broken unit tests if another constructor injected dependency is added, and to be able to generate a default object with something there for the dependencies, presumably to avoid null reference exceptions.
I would assume after reading the AutoMoq project page that if Darren were writing your particular unit test, he would probably just use Moq out of the box. That is, for that particular test, you should probably go with the test that you have posted. AutoMoq appears to aim at supplying sensible default behavior for when you don't want to bother specifying all of your dependencies in a test. But in your case, you do want to specify those particular dependencies.
Just because you use regular Moq for that particular test doesn't mean that you can't use AutoMoq for other tests. The rest of your tests (where both ints are zero or whatever) will be future-proofed, but you may just have to live with that one breaking if you add another constructor parameter to your Dummy class.
(You could also always snag the source code for AutoMoq and modify it to your needs).
Solution similar to Moq
You can create an instance of Dummy in AutoMoq very similar as you do in Moq.
This does not future proof your testcode against changes in the constructor parameters, but may still be acceptable.
var mocker = new AutoMoqer();
var fooMock = mocker.GetMock<IFoo>();
var dummy = new Dummy(1, 2, fooMock.Object);
// test something about dummy
Solution with AutoMoq
If you really want to future proof your TestCode, then it may be neccessary to change the constructor to depend on interfaces.
interface IDummyParameters {
int SomeInt {get;set;}
int SomeOtherInt {get;set;}
}
public class Dummy {
public Dummy(IDummyParameters parameters, IFoo foo){
...
}
}
Then you can create your Dummy class with AutoMoq like this:
var mocker = new AutoMoqer();
mocker.GetMock<IDummyParameters>.Setup(x => x.SomeInt).Returns(1);
mocker.GetMock<IDummyParameters>.Setup(x => x.SomeOtherInt).Returns(2);
// notice how this code does not say anything about IFoo.
// It is created automatically by AutoMoq
var dummy = mocker.Create<Dummy>();

Categories

Resources