I'm writing a unit test for my Abstract class using AutoFixture, this is a representation of what I'm trying to do:
public abstract class Base
{
public virtual void DoSomethingCool()
{
OnDoingSomethingCool();
}
protected abstract void OnDoingSomethingCool();
}
My unit test would look like this:
[TestMethod]
public void TestMethod1()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var sut = fixture.Create<Base>();
// How to assert that the OnDoingSomethingCool method was called
sut.Invoking(x => x.DoSomethingCool())
.ShouldNotThrow();
}
So how do I assert that the protected abstract method was actually called in the DoSomethingCool method??
If it were an object from an injected dependency, I would be able to setup a mock using Moq and assert that the method was called, but since the method is an abstract method inside my Subject Under Test, how do I assert the method was called?
There is a bunch that can be said about this:
It seems like you might be either testing too much, or giving too much control to other implementations.
(Too much control) Usually, if you want to force a method to be called from another method in your abstract class you do not make it public virtual. By doing this, you have given the future implementations the ability to change this behavior. In fact, if you remove the virtual, then you can get the test you want (see below). I did provide a way to keep the virtual, but again...not recommended. This is not recommended since your SUT is your mock...which doesn't feel right.
(Testing too much) You should only care about basic behavior, not implementation details, lest your tests become too brittle. I am assuming that there is more than just the call to the OnDoingSomethingCool method, otherwise you should just make that your main method. If the primary behavior is this call (and there is more than just this call), then I do cover that in my NotRecommended method below.
You should not test the abstract class directly. You should probably use what Roy Osherove calls the Abstract Test Class Pattern in The Art of Unit Testing. This makes it so that all implementations test your behavior. You can then pass in a dependency. If you would like that example or even a simplified example off the Abstract Test Class Pattern, let me know
/
using Moq.Protected;
...
public void NotRecommended_ProbablyTestingTooMuch_BrittleTestBelow
{
//If you MUST keep DoSomethingCool virtual
//var baseMock = new Mock<Base>{CallBase = true};
var baseMock = new Mock<Base>();
baseMock.Protected().Setup("OnDoingSomethingCool");
baseMock.Object.DoSomethingCool();
baseMock.Protected().Verify("OnDoingSomethingCool", Times.AtLeastOnce());
}
Related
I'm new to Moq
I read a lot about Moq testing and that you shouldn't test your mock object, instead you should use Moq to stub dependencies and make it to act like you want to. But now I am asking myself, how can you test if a method be called from another method in the same class, like this code:
public class A // --> class i want to test
{
public virtual void TestMethod() // --> does it call testmethod2
{
TestMethod2();
}
public virtual void TestMethod2()
{
// Do something
}
}
I thought I can write the Unittest like this:
[TestMethod]
public void MyTestMethod()
{
Mock<A> aMock = new Mock<A>();
aMock.Verify(o => o.TestMethod2(), Times.Once);
aMock.TestMethod();
aMock.VerifyAll();
}
But is this valid? Thank you for all good answers!
Moq is only able to mock out methods which are virtual (or provide mock implementations for interfaces). If you try a Setup or Verify on a non-virtual member, you'll get the error
Invalid verify on a non-virtual member: m => m.TestMethod2()
In your case, you would need to change TestMethod2 to virtual, i.e.
public virtual void TestMethod2()
Which can then be tested:
var aMock = new Mock<A>();
aMock.Object.TestMethod();
aMock.Verify(m => m.TestMethod2(), Times.Once);
As you've suggested, testing whether a class calls methods internal to itself is a smell, indication that you're either
Testing internal implementation detail (e.g. if TestMethod2() was private, it's none of our business to even know about it).
Or, an indication that the Class / System under test is in need of refactoring into multiple classes, which should be loosely coupled, and hence can be isolated and better testable.
Note
You can't Verify a call before you've invoked the method on the SUT that you want to test, i.e. move the Verify to after the invocation of .TestMethod() as I've done.
Although you could change your code to use the Setup + VerifyAll approach to testing, i.e. ensuring that everything you've setup is actually invoked:
aMock.Setup(m => m.TestMethod2());
aMock.Object.TestMethod();
aMock.VerifyAll();
There is however debate around whether the usage of VerifyAll violates AAA principals (since you're also in effect specifying the Verify criteria in the Arrange piece), and I've also found that this approach makes it impossible to refactor and DRY up Mock setups in large scale tests, and you also lose some of the finer level of checking (e.g. Times.Once).
I want to write unit test for private method in C# using moq framework, I've search in StackOverFlow and Google, but I cannot find the expected result. Please help me if you can.
You can't, at least not with Moq.
But more importantly, you shouldn't.
First off, you don't test methods, you test behaviours. Second, in order to test behaviours, you exercise a type's public API and verify the outcomes of that exercise.
Private methods are implementation details. You don't want to verify how things get done, you want to verify that things do get done.
In the AssemblyInfo.cs of your project add
[assembly: InternalsVisibleTo("Namespace.OfYourUnitTest.Project")]
then you make the method internal instead of private.
It has the benefit of avoiding to make it public.
However as pointed by dcastro, some people strongly disagree with this way of testing.
Perhaps you shouldn't (see other answers for why), but you can do this using Microsoft's Visual Studio Test Tools. A simplified example is given below.
Given the following class which you want to test:
public class ClassToTest
{
private int Duplicate(int n)
{
return n*2;
}
}
You can use the following code to test the private Duplicate method:
using Microsoft.VisualStudio.TestTools.UnitTesting;
// ...
[TestMethod]
public void MyTestMethod()
{
// Arrange
var testClass = new ClassToTest();
var privateObject = new PrivateObject(testClass);
// Act
var output = (int) privateObject.Invoke("Duplicate", 21);
// Assert
Assert.AreEqual(42, output);
}
Simply, you don't. Private methods are not visible to other classes.
There are a number of ways around this:
Treat the private as part of the method you're testing, cover it in their unit tests. Think of the public methods as black boxes and test their operations.
Make it protected and inherit your test class from the class you're testing (or use a partial - same idea)
Make it public (which if you're coding to an interface doesn't actually expose it to your consumers)
For public methods (option three) it is possible to partial mock the class where you can replace the method. In Moq you can do this like this:
var moq = new Mock<MyClass>();
moq.CallBase = true;
moq.Setup(x => x.MyPublicMethodToOverride()).Returns(true);
There are more details here.
Moq supports mocking protected methods. Changing the methods to protected, instead of private, would allow you to mock their implementation.
The following is from Moq Quickstart Documentation (deep link):
Setting expectations for protected members (you can't get IntelliSense
for these, so you access them using the member name as a string).
Assuming the following class with a protected function should be
mocked:
public class CommandBase {
protected virtual int Execute(); // (1)
protected virtual bool Execute(string arg); // (2)
}
// at the top of the test fixture
using Moq.Protected;
// In the test, mocking the `int Execute()` method (1)
var mock = new Mock<CommandBase>();
mock.Protected()
.Setup<int>("Execute")
.Returns(5);
// If you need argument matching, you MUST use ItExpr rather than It
// planning on improving this for vNext (see below for an alternative in Moq 4.8)
// Mocking the `bool Execute(string arg)` method (2)
mock.Protected()
.Setup<bool>("Execute",
ItExpr.IsAny<string>())
.Returns(true);
Moq 4.8 and later allows you to set up protected members through a
completely unrelated type that has the same members and thus provides
the type information necessary for IntelliSense to work. Pickin up the
example from the bullet point above, you can also use this interface
to set up protected generic methods and those having by-ref
parameters:
// Completely unrelated Interface (CommandBase is not derived from it) only created for the test.
// It contains a method with an identical method signature to the protected method in the actual class which should be mocked
interface CommandBaseProtectedMembers
{
bool Execute(string arg);
}
mock.Protected().As<CommandBaseProtectedMembers>()
.Setup(m => m.Execute(It.IsAny<string>())) // will set up CommandBase.Execute
.Returns(true);
I have a test (code is below) to test that Method1 calls Method2. The exception I'm getting is
The current proxy generator can not intercept the specified method for
the following reason: - Sealed methods can not be intercepted.
The method under test isn't sealed itself. However, it does have a dependency on a sealed class (a third-party class for which I am having trouble creating a wrapper in order to mock it properly - another topic for another question). Either way, at this point I'm not asking FakeItEasy to mock the sealed class. And while debugging my test, when the dependency is called, I can clearly see that a real object is being produced, not a fake.
And yet, given the error message, I feel like it might be related somehow.
Further, I discovered through a random blog post that making the method virtual fixes the problem, allowing the test to pass. I gave it a try and it worked. But I don't get why it fixed it, and regardless, it doesn't make sense for me to keep the method virtual. In my case, the class being tested doesn't have any children of its own, ie; no children to override its methods, so I can't see any reason to make it virtual.
Am I wrong in thinking I have no reason to make the method virtual?
Is FakeItEasy somehow trying to mock that sealed class?
I'm really not sure how to proceed with this test.
My Test
[SetUp]
public void SetUp()
{
// Arrange
_service2 = A.Fake<Service2>(x => x.WithArgumentsForConstructor(
() => new Service2()));
_service1 = A.Fake<Service1>(x => x.WithArgumentsForConstructor(
() => new Service1(_service2)));
}
[Test]
public void when_Method1_executes_it_calls_Method2()
{
// Act
result = _service1.Method1();
// Assert
A.CallTo(() => _service2.Method2())
.WithAnyArguments()
.MustHaveHappened();
}
Related Methods
public class Service1 : IService1
{
private readonly IService2 _service2;
public Service1(IService2 service2)
{
_service2 = service2;
}
public bool Method1()
{
using (var dependency = new MyDependency()) // third party sealed class
{
}
var x = _service2.Method2();
}
}
public class Service2 : IService2
{
public bool Method2() // making this virtual fixes the FakeItEasy exception
{
}
}
While normally applied to the class scope, sealed in this case refers to the inability to override the method in question. Using sealed with a method is only valid if the method is an override - however, methods which are not virtual in the first place cannot be overidden, and are thus themselves implicitly sealed.
What this error refers to is that it cannot accept non-virtual methods, due to the fact that it is creating a class on the fly inherited from your given class to perform these intercepts. At such a level, it can neither determine the difference between a non-vritual and sealed method, nor does it need to - it cannot override, and thus cannot insert the appropriate intercept.
Aravol's answer is great. I urge you to accept it and/or vote it up.
There's another approach, though. Make _service2 a fake IService2.
Then you don't have to change the signature of any methods (interface methods are always overridable/interceptable). In general, it's easier to fake interface interfaces than concrete (or even abstract) classes, and it has the nice effect of actually testing that your collaborating classes can work with interfaces, not necessarily just with particular implementations of the interfaces.
While I'm here, and this part isn't really related to your error, but may help make your code a little clearer, since you're testing Service1, I would not fake it; use an actual Service1 instance. This makes it clear to readers what's actually being tested. Faking the system under test is widely considered to be a code smell.
If you happened to take both these points, your SetUp would look a little more like this:
[SetUp]
public void SetUp()
{
// Arrange
_service2 = A.Fake<IService2>();
_service1 = new Service1(_service2);
}
And your test should pass.
I've just been chasing a nearly identical problem for two days now. Blair Conrad's solution above of faking at the interface level worked for me, and also actually makes sense:
If the class being tested doesn't have a dependency on another class, neither should the test. Therefore you fake the interface, rather than a class that implements the interface.
I have an abstract class that has a virtual method. The method is virtual in the event that a later implementation needs to override that functionality.
However, Moq proxies all virtual methods so I don't seem to be able to test the actual code that's written, and instead uses the Mock setup for that method (which is currently to return the default value).
Example abstract:
public abstract SomeAbstract
{
public abstract Format(IFormatProvider provider, string format)
{
// does some stuff i need to test
}
}
My NUnit test:
[Test]
public void Should_Set_Format_State()
{
Mock<SomeAbstract> mock = new Mock<SomeAbstract>();
mock.Object.Format(CultureInfo.CurrentCulture, "format string");
// do tests to make sure Format correctly changed the object's state
}
How do I set up my Mock object to just let my virtual Format method work, without having to remove virtual from the method?! Perhaps I'm abusing the mocking concept in this case.
I believe setting "CallBase = true" on the mock will work. See the "Customizing Mock Behavior" section of the Quick Start
Using Moq, I have a very odd issue where the setup on a mock only seems to work if the method I am setting up is public. I don't know if this is a Moq bug or if I just have this wrong (newbie to Moq). Here is the test case:
public class TestClass
{
public string Say()
{
return Hello();
}
internal virtual string Hello()
{
return "";
}
}
[TestMethod]
public void Say_WhenPublic_CallsHello()
{
Mock<TestClass> mock = new Mock<TestClass>();
mock.Setup(x => x.Hello()).Returns("Hello World");
string result = mock.Object.Say();
mock.Verify(x => x.Hello(), Times.Exactly(1));
Assert.AreEqual("Hello World", result);
}
Which fails with this message:
Say_WhenPublic_CallsHello failed: Moq.MockException:
Invocation was not performed on the mock 1 times: x => x.Hello()
at Moq.Mock.ThrowVerifyException(IProxyCall expected, Expression expression, Times times)...
If I make the Hello method public like this, the test passes. What is the issue here?
public virtual string Hello()
{
return "";
}
Thanks in advance!
The test fails when Hello() is internal because Moq cannot provide an override of the method in this case. This means that the internal implementation of Hello() will run, rather than mock's version, causing the Verify() to fail.
Incidentally, what you are doing here makes no sense in the context of a unit test. A unit test should not care that Say() calls an internal Hello() method. This is implementation internal to your assembly and not a concern of consuming code.
I don't know enough about how this works underneath the covers to give you a technical answer as to exactly why that is the behaviour, but I think I can help with your confusion.
In your example you are calling a method Say(), and it is returning the expected text. Your expectation should not enforce a particular implementation of Say() ie that it calls an internal method called Hello() to return that string. This is why it does not pass the verify, and also why the string returned is "", ie the actual implementation of Hello() has been called.
By making the Hello method public it appears that this has enabled Moq to intercept the call to it, and use it's implementation instead. Therefore, in this case the test appears to pass. However, in this scenario you haven't really achieved anything useful, because your test says that when you call Say() the result is "Hello World" when in acutal fact the result is "".
I have rewritten your example to show how I would expect Moq to be used (not necessarily definitive, but hopefully clear.
public interface IHelloProvider
{
string Hello();
}
public class TestClass
{
private readonly IHelloProvider _provider;
public TestClass(IHelloProvider provider)
{
_provider = provider;
}
public string Say()
{
return _provider.Hello();
}
}
[TestMethod]
public void WhenSayCallsHelloProviderAndReturnsResult()
{
//Given
Mock<IHelloProvider> mock = new Mock<IHelloProvider>();
TestClass concrete = new TestClass(mock.Object);
//Expect
mock.Setup(x => x.Hello()).Returns("Hello World");
//When
string result = concrete.Say();
//Then
mock.Verify(x => x.Hello(), Times.Exactly(1));
Assert.AreEqual("Hello World", result);
}
In my example, I have introduced an interface to an IHelloProvider. You will notice that there is no implementation of IHelloProvider. This is at the heart of what we are trying to achieve by using a mocking solution.
We are trying to test a class (TestClass), which is dependant on something external (IHelloProvider). If you are using Test Driven Development then you probably haven't written an IHelloProvider yet, but you are aware that you will need one at some point. You want to get TestClass working first though, rather than get distracted. Or perhaps IHelloProvider uses a database, or a flat file, or is difficult to configure.
Even if you have a fully working IHelloProvider, you are still only trying to test the behaviour of TestClass, so using a concrete HelloProvider is likely to make your test more prone to failure, for instance if there is a change to the behaviour of HelloProvider, you don't want to have to change the tests of every class that uses it, you just want to change the HelloProvider tests.
Getting back to the code, we now have a class TestClass, which is dependant on an interface IHelloProvider, the implementation of which is provided at construction time (this is dependency injection).
The behaviour of Say() is that it calls the method Hello() on the IHelloProvider.
If you look back at the test, we have created an actual TestClass object, since we actually want to test the code that we have written. We have created a Mock IHelloProvider, and said that we expect it to have it's Hello() method called, and when it does to return the string "Hello World".
We then call Say(), and verify the results as before.
The important thing to realise is that we are not interested in the behaviour of the IHelloProvider, and so we can mock it to make testing easier. We are interested in the behaviour of TestClass, so we have created an actual TestClass not a Mock, so that we can test it's actual behaviour.
I hope this has helped to clarify what is going on.
Moq doesn't do partial mocking and can only mock public virtual methods or interfaces. When you create a Mock you are creating a completely new T and removing all implementation of any public virtual methods.
My suggestion would be to concentrate on testing the public surface area of your objects and not their internals. Your internals will get coverage. Just make sure you have a clear idea of what your target class is and don't mock that (in most cases).
Partial mocking is only useful when you want to test the functionality of an abstract class with mocked implementations of abstract methods. If you aren't doing this, you are likely not going to see much benefit from doing a partial mock.
If this is not an abstract class, you will want to focus more on the approach Modan suggests, which is to say that you should mock dependencies rather than your target class itself. All of this boils down to the rule don't mock what you are testing.