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

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

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.

force relay to mocking framework

I would like to create a customization that configures AutoFixture to pass types it DOES have implementations for off to Moq instead. How can I do that generically?
To clarify, consider:
public class test
{
public string foo;
public test(IDictionary<string, string> stuffing)
{
foo = stuffing["bogus"];
}
}
[TestMethod]
public void testInjection()
{
var fixture = new Fixture();
bool didThrow;
try
{
var sut = fixture.Create<test>();
didThrow = false;
}
catch
{
didThrow = true;
}
Assert.IsTrue(didThrow);
}
The test passes. AutoFixture has provided me with a dummy collection compatible with IDictionary. I would like the test to fail... specifically, I'd like to hand the IDictionary off to Moq and get something that doesn't complain about missing keys by default.
I'd like to use something like fixture.UseAutoMoq().ForceRelay<Dictionary<string,string>>().
I'm also open to better suggestions... but consider the test class sealed. I'm testing into code that uses this pattern a lot and I want a test convention around it.
To do what you ask for, you can take the MockRelay added by AutoMoqCustomization and move it in front of the well-known-collections-builders:
[Fact]
public void PassByMovingAutoMoqRelay()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var relay = fixture.ResidueCollectors.OfType<MockRelay>().Single();
fixture.Customizations.Add(relay);
var sut = fixture.Create<MyClass>(); // Doesn't throw
}
However, I don't think it's a good idea, as most of the .NET collection interfaces are big fat LSP violations, and there's no guarantee that auto-mocking them will produce meaningful behaviours - I'd expect the opposite to be the case.

How do you mock a void method that sets a read-only property?

I'm not very familiar with RhinoMocks and I'm trying to break into TDD on a side project of mine. I've been moving along okay until I hit a wall trying to get this behavior under test.
private int _result;
public int Result { get { return _result; } }
public void GetRandomValue()
{
Random n = new Random();
_result = n.Next(1,100);
}
Since this is an abstract class, how can I use RhinoMocks to verify that when I call the GetRandomValue method that the Result property is set? Or is this a necessary test? Or a better way to design this small bit of code?
The way I would go about testing it is
var randomizerClass = new RandomizerClass();
ranomizerClass.GetRandomValue();
var result = ranomizerClass.Result;
Assert.IsTrue(result > 0 && result < 101);
And the ranomizerClass is the concrete implementation of the abstract class. You don't need to separately test your abstract class since that will be done through the concrete implementation
Maybe you should extract the interface from the abstract class and simply implement the mock for it with corresponding methods?
Presumably when you instantiate the type, the _result field is set to it's default value of 0. So can't you just create an instance of the type, call the method, and then check the value of the Result property doesn't equal 0?
It seems odd that a method called GetRandomValue, doesn't actually return anything. Is there a reason why this method doesn't return the result? Also, I would instantiate your Random type outside the scope of the method.
How can you test that you're getting a random number? It's random, so you can't write a test that's actually asserting anything useful. You could make an IRandomNumberProvider interface and implement it on a RandomNumberProvider, then mock that for testing purposes, but you wouldn't be testing anything of value in my opinion. Even if you did like some other folks suggested and asserted that the number is between 1 and 100, you haven't tested anything useful in your code, you've just ensured that Microsoft's implementation of Next is working, which is a given.
Your GetRandomValue() method shouldn't set Result, though. It should return the result. Otherwise, you've introduced a side effect into your class, and that generally can cause weird, hard-to-track-down bugs.
In the cases where you need to test functionality in an abstract class, simply create a class that implements it in your test project.
E.g. given the following class
public abstract class MyClass
{
private int _result;
public int Result { get { return _result; } }
public void GetRandomValue()
{
Random n = new Random();
_result = n.Next(1,100);
}
}
Create a test class in your test project
public class StubMyClass : MyClass
{
}
and then test it as follows
[Test]
public void ShouldSetResultAfterCallingGetRandomValue()
{
var myClass = new StubMyClass();
myClass.GetRandomValue();
int expected = 1234;
Assert.That(myClass.Result, Is.EqualTo(expected));
}

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>();

How to mock class members in 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'.

Categories

Resources