I changed the api to sub.DoSomething().Returns(x => x.CallBase())

This commit is contained in:
Alexandr Nikitin 2013-07-22 01:01:34 +03:00 коммит произвёл David Tchepak
Родитель b3ae935769
Коммит 5de8edf0b5
7 изменённых файлов: 211 добавлений и 263 удалений

Просмотреть файл

@ -4,206 +4,230 @@ using NUnit.Framework;
namespace NSubstitute.Acceptance.Specs
{
// todo move tests to proper place, add more?
public class CallBaseForMember
{
[Test]
public void Given_SubstituteForInterface_When_MethodIsCalled_Then_ShouldThrowException()
public class WhenCalledDoCallBase
{
var testAbstractClass = Substitute.For<ITestInterface>();
Assert.Throws<CouldNotCallBaseException>(() => testAbstractClass.CallBaseFor().TestMethod());
[Test]
public void Given_SubstituteForInterface_When_MethodIsCalled_Then_ShouldThrowException()
{
var testInterface = Substitute.For<ITestInterface>();
testInterface.When(x => x.VoidTestMethod()).Do(x => x.CallBase());
Assert.Throws<CouldNotCallBaseException>(testInterface.VoidTestMethod);
}
[Test]
public void Given_SubstituteForAbstractClass_When_AbstractMethodIsCalled_Then_ShouldThrowException()
{
var testAbstractClass = Substitute.For<TestAbstractClass>();
testAbstractClass.When(x => x.VoidAbstractMethod()).Do(x => x.CallBase());
Assert.Throws<CouldNotCallBaseException>(testAbstractClass.VoidAbstractMethod);
}
[Test]
public void Given_SubstituteForAction_When_ActionIsCalled_Then_ShouldThrowException()
{
var action = Substitute.For<Action>();
action.When(x => x.Invoke()).Do(x => x.CallBase());
Assert.Throws<CouldNotCallBaseException>(() => action());
}
[Test]
public void Given_SubstituteForFunc_When_FuncIsCalled_Then_ShouldThrowException()
{
var func = Substitute.For<Func<int>>();
func.When(x => x.Invoke()).Do(x => x.CallBase());
Assert.Throws<CouldNotCallBaseException>(() => func());
}
[Test]
public void Given_SubstituteForEventHandler_When_EventHandlerIsCalled_Then_ShouldThrowException()
{
var eventHandler = Substitute.For<EventHandler>();
eventHandler.When(x => x.Invoke(Arg.Any<object>(), Arg.Any<EventArgs>())).Do(x => x.CallBase());
Assert.Throws<CouldNotCallBaseException>(() => eventHandler(null, null));
}
[Test]
public void Given_SubstituteForClass_When_VirtualMethodIsCalled_Then_ShouldCallBaseImplementation()
{
var testClass = Substitute.For<TestClass>();
testClass.When(x => x.VoidVirtualMethod()).Do(x => x.CallBase());
testClass.VoidVirtualMethod();
Assert.That(testClass.CalledTimes, Is.EqualTo(1));
}
[Test]
public void Given_SubstituteForClass_When_VirtualMethodIsSetup_ShouldNotCallRealImplementation()
{
var testClass = Substitute.For<TestClass>();
testClass.When(x => x.VoidVirtualMethod()).Do(x => x.CallBase());
testClass.When(x => x.VoidVirtualMethod()).Do(x => x.CallBase());
Assert.That(testClass.CalledTimes, Is.EqualTo(0));
}
[Test]
public void Given_SubstituteForClass_When_VirtualMethodIsSetupTwice_Then_ShouldSetupCorrectly()
{
var testClass = Substitute.For<TestClass>();
testClass.When(x => x.VoidVirtualMethod()).Do(x => x.CallBase());
testClass.When(x => x.VoidVirtualMethod()).Do(x => x.CallBase());
testClass.VoidVirtualMethod();
// I doubt that we should call base implementation just once here
// as .When().Do() syntax purpose is to invoke actions and not Return/Callbase
// and just by accident we have two actions that call base implemenation
Assert.That(testClass.CalledTimes, Is.EqualTo(2));
}
[Test]
public void Given_SubstituteForClass_When_AbstractMethodIsCalled_Then_ShouldCallBaseImplementation()
{
var testClass = Substitute.For<TestClass>();
testClass.When(x => x.VoidAbstractMethod()).Do(x => x.CallBase());
testClass.VoidAbstractMethod();
Assert.That(testClass.CalledTimes, Is.EqualTo(1));
}
[Test]
public void Given_SubstituteForClass_When_VirtualMethodIsCalledTwice_Then_ShouldCallBaseImplementationTwice()
{
var testClass = Substitute.For<TestClass>();
testClass.When(x => x.VoidVirtualMethod()).Do(x => x.CallBase());
testClass.VoidVirtualMethod();
testClass.VoidVirtualMethod();
Assert.That(testClass.CalledTimes, Is.EqualTo(2));
}
[Test]
public void Given_SubstituteForAbstractClass_When_MethodWithImplementationIsCalled_Then_ShouldCallBaseImplementation()
{
var testAbstractClass = Substitute.For<TestAbstractClass>();
testAbstractClass.When(x => x.MethodReturnsSameInt(Arg.Any<int>())).Do(x => x.CallBase());
// .When().Do() syntax does not return value from base implementation
Assert.That(testAbstractClass.MethodReturnsSameInt(1), Is.EqualTo(default(int)));
// but it calls base implementation
Assert.That(testAbstractClass.CalledTimes, Is.EqualTo(1));
}
}
[Test]
public void Given_SubstituteForAbstractClass_When_AbstractMethodIsCalled_Then_ShouldThrowException()
public class ReturnsCallBase
{
var testAbstractClass = Substitute.For<TestAbstractClass>();
Assert.Throws<CouldNotCallBaseException>(() => testAbstractClass.CallBaseFor().AbstractMethod());
}
[Test]
public void Given_SubstituteForInterface_When_MethodIsCalled_Then_ShouldThrowException()
{
var testInterface = Substitute.For<ITestInterface>();
testInterface.TestMethodReturnsInt().Returns(x => x.CallBase());
Assert.Throws<CouldNotCallBaseException>(() => testInterface.TestMethodReturnsInt());
}
[Test]
public void Given_SubstituteForAction_When_ActionIsCalled_Then_ShouldThrowException()
{
var action = Substitute.For<Action>();
Assert.Throws<CouldNotCallBaseException>(() => action.CallBaseFor().Invoke());
}
[Test]
public void Given_SubstituteForAbstractClass_When_AbstractMethodIsCalled_Then_ShouldThrowException()
{
var testAbstractClass = Substitute.For<TestAbstractClass>();
testAbstractClass.AbstractMethodReturnsSameInt(Arg.Any<int>()).Returns(x => x.CallBase());
Assert.Throws<CouldNotCallBaseException>(() => testAbstractClass.AbstractMethodReturnsSameInt(1));
}
[Test]
public void Given_SubstituteForFunc_When_FuncIsCalled_Then_ShouldThrowException()
{
var func = Substitute.For<Func<int>>();
Assert.Throws<CouldNotCallBaseException>(() => func.CallBaseFor().Invoke());
}
[Test]
public void Given_SubstituteForFunc_When_FuncIsCalled_Then_ShouldThrowException()
{
var func = Substitute.For<Func<int>>();
func().Returns(x => x.CallBase());
Assert.Throws<CouldNotCallBaseException>(() => func());
}
[Test]
public void Given_SubstituteForEventHandler_When_EventHandlerIsCalled_Then_ShouldThrowException()
{
var eventHandler = Substitute.For<EventHandler>();
Assert.Throws<CouldNotCallBaseException>(() =>
eventHandler.CallBaseFor().Invoke(Arg.Any<object>(), Arg.Any<EventArgs>()));
}
[Test]
public void Given_SubstituteForAbstractClass_When_MethodWithImplementationIsCalled_Then_ShouldCallBaseImplementation()
{
var testAbstractClass = Substitute.For<TestAbstractClass>();
testAbstractClass.MethodReturnsSameInt(Arg.Any<int>()).Returns(x => x.CallBase());
Assert.That(testAbstractClass.MethodReturnsSameInt(1), Is.EqualTo(1));
Assert.That(testAbstractClass.CalledTimes, Is.EqualTo(1));
}
[Test]
public void
Given_SubstituteForAbstractClass_When_MethodWithImplementationIsCalled_Then_ShouldCallBaseImplementation
()
{
var testAbstractClass = Substitute.For<TestAbstractClass>();
testAbstractClass.CallBaseFor().MethodWithImplementation(Arg.Any<int>());
Assert.That(testAbstractClass.MethodWithImplementation(1), Is.EqualTo(1));
}
[Test]
[Ignore("Should/can we avoid call base here?")]
public void
Given_SubstituteForClass_When_VirtualMethodsReturnValueIsOverwritten_Then_ShouldNotCallBaseImplementation
()
{
var testClass = Substitute.For<TestClass>();
testClass.VirtualMethodReturnsSameInt(Arg.Any<int>()).Returns(x => x.CallBase());
testClass.VirtualMethodReturnsSameInt(Arg.Any<int>()).Returns(1);
Assert.That(testClass.CalledTimes, Is.EqualTo(0));
}
[Test]
public void Given_SubstituteForClass_When_VirtualMethodIsCalled_Then_ShouldCallBaseImplementation()
{
var testClass = Substitute.For<TestClass>();
testClass.CallBaseFor().VirtualMethod();
testClass.VirtualMethod();
Assert.That(testClass.CalledTimes, Is.EqualTo(1));
}
[Test]
public void
Given_SubstituteForClass_And_ReturnValueIsOverwritten_When_VirtualMethodIsCalled_Then_ShouldReturnOverwrittenValue
()
{
var testClass = Substitute.For<TestClass>();
testClass.VirtualMethodReturnsSameInt(Arg.Any<int>()).Returns(x => x.CallBase());
testClass.VirtualMethodReturnsSameInt(Arg.Any<int>()).Returns(2);
Assert.That(testClass.VirtualMethodReturnsSameInt(1), Is.EqualTo(2));
}
[Test]
public void Given_SubstituteForClass_When_CallBaseUsed_ShouldNotCallRealImplementation()
{
var testClass = Substitute.For<TestClass>();
testClass.CallBaseFor().VirtualMethod();
testClass.CallBaseFor().VirtualMethod();
[Test]
public void
Given_SubstituteForClass_And_VirtualMethodReturnsFuncs_When_VirtualMethodIsCalled_Then_ShouldReturnCorrectValues
()
{
var testClass = Substitute.For<TestClass>();
testClass.VirtualMethodReturnsSameInt(Arg.Any<int>())
.Returns(
x => x.CallBase(),
x => 1,
x => { throw new Exception(); });
Assert.That(testClass.VirtualMethodReturnsSameInt(2), Is.EqualTo(2));
Assert.That(testClass.VirtualMethodReturnsSameInt(2), Is.EqualTo(1));
Assert.Throws<Exception>(() => testClass.VirtualMethodReturnsSameInt(1));
}
Assert.That(testClass.CalledTimes, Is.EqualTo(0));
}
[Test]
public void Given_SubstituteForClass_When_VirtualMethodIsSetupTwice_Then_ShouldSetupCorrectly()
{
var testClass = Substitute.For<TestClass>();
testClass.CallBaseFor().VirtualMethod();
testClass.CallBaseFor().VirtualMethod();
testClass.VirtualMethod();
Assert.That(testClass.CalledTimes, Is.EqualTo(1));
}
[Test]
public void Given_SubstituteForClass_When_AbstractMethodIsCalled_Then_ShouldCallBaseImplementation()
{
var testClass = Substitute.For<TestClass>();
testClass.CallBaseFor().AbstractMethod();
testClass.AbstractMethod();
Assert.That(testClass.CalledTimes, Is.EqualTo(1));
}
[Test]
public void Given_SubstituteForClass_When_VirtualMethodIsCalledTwice_Then_ShouldCallBaseImplementationTwice()
{
var testClass = Substitute.For<TestClass>();
testClass.CallBaseFor().VirtualMethod();
testClass.VirtualMethod();
testClass.VirtualMethod();
Assert.That(testClass.CalledTimes, Is.EqualTo(2));
}
[Test]
public void
Given_SubstituteForClass_When_VirtualMethodsReturnValueIsOverwritten_Then_ShouldNotCallBaseImplementation
()
{
var testClass = Substitute.For<TestClass>();
testClass.CallBaseFor().VirtualMethodReturnsSameInt(Arg.Any<int>());
testClass.VirtualMethodReturnsSameInt(Arg.Any<int>()).Returns(1);
Assert.That(testClass.CalledTimes, Is.EqualTo(0));
}
[Test]
public void
Given_SubstituteForClass_And_ReturnValueIsOverwritten_When_VirtualMethodIsCalled_Then_ShouldReturnOverwrittenValue
()
{
var testClass = Substitute.For<TestClass>();
testClass.CallBaseFor().VirtualMethodReturnsSameInt(Arg.Any<int>());
testClass.VirtualMethodReturnsSameInt(Arg.Any<int>()).Returns(2);
Assert.That(testClass.VirtualMethodReturnsSameInt(1), Is.EqualTo(2));
}
[Test]
public void
Given_SubstituteForClass_And_ObjectReturnValueIsOverwritten_When_VirtualMethodIsCalled_Then_ShouldReturnOverwrittenValue
()
{
var testClass = Substitute.For<TestClass>();
testClass.CallBaseFor().VirtualMethodReturnsSameObject(Arg.Any<object>());
var objectToReturn = new object();
testClass.VirtualMethodReturnsSameObject(Arg.Any<object>()).Returns(objectToReturn);
Assert.That(testClass.VirtualMethodReturnsSameObject(new object()), Is.EqualTo(objectToReturn));
}
[Test]
public void
Given_SubstituteForClass_And_SubstituteDoesNotOverwriteReturn_When_VirtualMethodIsCalled_Then_ShouldCallBaseImplementation
()
{
var testClass = Substitute.For<TestClass>();
var objectCallBase = new object();
testClass.CallBaseFor().VirtualMethodReturnsSameObject(Arg.Is(objectCallBase));
var objectCallSubstitute = new object();
testClass.VirtualMethodReturnsSameObject(Arg.Is(objectCallSubstitute)).Returns(new object());
Assert.That(testClass.VirtualMethodReturnsSameObject(objectCallBase), Is.EqualTo(objectCallBase));
}
[Test]
public void
Given_SubstituteForClass_And_SubstituteDoesOverwriteReturn_When_VirtualMethodIsCalled_Then_ShouldReturnOverwrittenValue
()
{
var testClass = Substitute.For<TestClass>();
var objectCallBase = new object();
testClass.CallBaseFor().VirtualMethodReturnsSameObject(Arg.Is(objectCallBase));
var objectToReturn = new object();
testClass.VirtualMethodReturnsSameObject(Arg.Is(objectCallBase)).Returns(objectToReturn);
Assert.That(testClass.VirtualMethodReturnsSameObject(objectCallBase), Is.EqualTo(objectToReturn));
}
[Test]
public void
Given_SubstituteForClass_And_VirtualMethodReturnValueForSpecifiedArg_When_VirtualMethodIsCalledWithSpecifiedArg_Then_ShouldReturnOverwrittenValue
()
{
var testClass = Substitute.For<TestClass>();
testClass.CallBaseFor().VirtualMethodReturnsSameInt(Arg.Any<int>());
testClass.VirtualMethodReturnsSameInt(Arg.Is(1)).Returns(2);
// substitute has higher priority than base implementation
Assert.That(testClass.VirtualMethodReturnsSameInt(1), Is.EqualTo(2));
Assert.That(testClass.CalledTimes, Is.EqualTo(0));
}
[Test]
public void
Given_SubstituteForClass_And_VirtualMethodReturnValueForSpecifiedArg_When_VirtualMethodIsCalledWithoutSpecifiedArg_Then_ShouldCallBaseImplementation
()
{
var testClass = Substitute.For<TestClass>();
testClass.CallBaseFor().VirtualMethodReturnsSameInt(Arg.Any<int>());
testClass.VirtualMethodReturnsSameInt(Arg.Is(1)).Returns(2);
Assert.That(testClass.VirtualMethodReturnsSameInt(3), Is.EqualTo(3));
Assert.That(testClass.CalledTimes, Is.EqualTo(1));
[Test]
public void
Given_SubstituteForClass_And_VirtualMethodReturnsFuncs_When_VirtualMethodIsCalled_Then_ShouldCallBaseCorrect
()
{
var testClass = Substitute.For<TestClass>();
testClass.VirtualMethodReturnsSameInt(Arg.Any<int>())
.Returns(
x => x.CallBase(),
x => 1,
x => 2);
testClass.VirtualMethodReturnsSameInt(1);
testClass.VirtualMethodReturnsSameInt(1);
testClass.VirtualMethodReturnsSameInt(1);
Assert.That(testClass.CalledTimes, Is.EqualTo(1));
}
}
public interface ITestInterface
{
void TestMethod();
void VoidTestMethod();
int TestMethodReturnsInt();
}
public abstract class TestAbstractClass
{
public abstract void AbstractMethod();
public int CalledTimes { get; set; }
public virtual int MethodWithImplementation(int i)
public abstract void VoidAbstractMethod();
public abstract int AbstractMethodReturnsSameInt(int i);
public virtual int MethodReturnsSameInt(int i)
{
CalledTimes++;
return i;
}
}
public class TestClass : TestAbstractClass
{
public int CalledTimes { get; set; }
public virtual int VirtualMethodReturnsSameInt(int i)
{
@ -217,15 +241,21 @@ namespace NSubstitute.Acceptance.Specs
return o;
}
public virtual void VirtualMethod()
public virtual void VoidVirtualMethod()
{
CalledTimes++;
}
public override void AbstractMethod()
public override void VoidAbstractMethod()
{
CalledTimes++;
}
public override int AbstractMethodReturnsSameInt(int i)
{
CalledTimes++;
return i;
}
}
}
}

Просмотреть файл

@ -189,7 +189,6 @@
<Compile Include="Core\IReturn.cs" />
<Compile Include="Core\PropertyCallFormatter.cs" />
<Compile Include="Core\ReflectionExtensions.cs" />
<Compile Include="Routing\Handlers\SetBaseForCallHandler.cs" />
<Compile Include="Routing\IRouteFactory.cs" />
<Compile Include="Routing\Route.cs" />
<Compile Include="Exceptions\ArgumentNotFoundException.cs" />

Просмотреть файл

@ -10,22 +10,18 @@ namespace NSubstitute.Proxies.CastleDynamicProxy
public virtual ICall Map(IInvocation castleInvocation)
{
//Func<object> baseMethod = null;
//if (castleInvocation.InvocationTarget != null &&
// castleInvocation.MethodInvocationTarget.IsAbstract != true)
//{
// baseMethod = () =>
// {
// castleInvocation.Proceed();
// return castleInvocation.ReturnValue;
// };
//}
Func<object> baseMethod = () =>
Func<object> baseMethod = null;
if (castleInvocation.InvocationTarget != null &&
castleInvocation.MethodInvocationTarget.IsVirtual &&
!castleInvocation.MethodInvocationTarget.IsAbstract &&
!castleInvocation.MethodInvocationTarget.IsFinal)
{
baseMethod = () =>
{
castleInvocation.Proceed();
return castleInvocation.ReturnValue;
};
}
return CallFactory.Create(castleInvocation.Method, castleInvocation.Arguments, castleInvocation.Proxy, baseMethod);
}

Просмотреть файл

@ -1,47 +0,0 @@
using System;
using System.Reflection;
using NSubstitute.Core;
using NSubstitute.Exceptions;
namespace NSubstitute.Routing.Handlers
{
public class SetBaseForCallHandler : ICallHandler
{
private readonly ICallSpecificationFactory _callSpecificationFactory;
private readonly ICallResults _callResults;
private readonly MatchArgs _matchArgs;
public SetBaseForCallHandler(ICallSpecificationFactory callSpecificationFactory, ICallResults callResults, MatchArgs matchArgs)
{
_callSpecificationFactory = callSpecificationFactory;
_callResults = callResults;
_matchArgs = matchArgs;
}
public RouteAction Handle(ICall call)
{
var method = call.GetMethodInfo();
if (!CanCallBase(method))
{
throw new CouldNotCallBaseException(method);
}
var callSpec = _callSpecificationFactory.CreateFrom(call, _matchArgs);
_callResults.SetResult(callSpec, new ReturnValueFromBase(method.ReturnType));
return RouteAction.Continue();
}
private bool CanCallBase(MethodInfo methodInfo)
{
return methodInfo.IsVirtual && !methodInfo.IsFinal && !methodInfo.IsAbstract;
}
class ReturnValueFromBase : IReturn
{
private readonly Type _expectedType;
public ReturnValueFromBase(Type expectedType) { _expectedType = expectedType; }
public object ReturnFor(CallInfo info) { return info.CallBase(); }
public Type TypeOrNull() { return _expectedType; }
public bool CanBeAssignedTo(Type t) { return _expectedType.IsAssignableFrom(t); }
}
}
}

Просмотреть файл

@ -5,7 +5,6 @@ namespace NSubstitute.Routing
{
public interface IRouteFactory
{
IRoute CallBase(ISubstituteState state, MatchArgs matchArgs);
IRoute CallQuery(ISubstituteState state);
IRoute CheckReceivedCalls(ISubstituteState state, MatchArgs matchArgs, Quantity requiredQuantity);
IRoute DoWhenCalled(ISubstituteState state, Action<CallInfo> doAction, MatchArgs matchArgs);

Просмотреть файл

@ -6,15 +6,6 @@ namespace NSubstitute.Routing
{
public class RouteFactory : IRouteFactory
{
public IRoute CallBase(ISubstituteState state, MatchArgs matchArgs)
{
return new Route(new ICallHandler[] {
new ClearLastCallRouterHandler(state.SubstitutionContext)
, new ClearUnusedCallSpecHandler(state)
, new SetBaseForCallHandler(state.CallSpecificationFactory, state.CallResults, matchArgs)
, ReturnDefaultForReturnTypeHandler()
});
}
public IRoute CallQuery(ISubstituteState state)
{
return new Route(new ICallHandler[] {

Просмотреть файл

@ -224,26 +224,6 @@ namespace NSubstitute
return GetRouterForSubstitute(substitute).ReceivedCalls();
}
/// <summary>
/// Calls base implementation for the specified member called with any args.
/// </summary>
public static T CallBaseWithAnyArgsFor<T>(this T substitute) where T : class
{
var router = GetRouterForSubstitute(substitute);
router.SetRoute(x => RouteFactory().CallBase(x, MatchArgs.Any));
return substitute;
}
/// <summary>
/// Calls base implementation for the specified member.
/// </summary>
public static T CallBaseFor<T>(this T substitute) where T : class
{
var router = GetRouterForSubstitute(substitute);
router.SetRoute(x => RouteFactory().CallBase(x, MatchArgs.AsSpecifiedInCall));
return substitute;
}
private static ICallRouter GetRouterForSubstitute<T>(T substitute)
{
var context = SubstitutionContext.Current;