I'm trying to setup unit testing for my API controllers. I'm using the mediatr pattern and FakeIteasy.
I have the following code.
public class ChannelGroupChannelsControllerTests
{
private readonly ChannelGroupChannelsController _controller;
private readonly IMediator _mediator;
public ChannelGroupChannelsControllerTests()
{
var service = A.Fake<IReadChannelGroupChannel>();
var mapper = A.Fake<IMapper>();
var channelGroupChannel = new ChannelGroupChannel
{
Id = 1,
ChannelGroupId = 1,
ChannelId = 1,
Channel = new Channel { Name = "Channel Name" }
};
_mediator = A.Fake<IMediator>();
_controller = new ChannelGroupChannelsController(_mediator, mapper);
A.CallTo(() => _mediator.Send(A<GetChannelGroupChannelById>._, A<CancellationToken>._)).Returns(channelGroupChannel);
}
[Fact]
public async Task ChannelGroupChannelsController_ById()
{
var result = await _controller.ById(1);
(result.Result as StatusCodeResult)?.StatusCode.Should().Be((int)HttpStatusCode.OK);
result.Value.Should().BeOfType<ChannelGroupChannelVM>();
}
}
Now the problem is that I keep getting NULL as a value.
I think the issue might be that GetChannelGroupChannelById has a constructor that expects the ID. But I'm not sure...
Does anybody know what could be wrong? I'm pretty new with the mocking stuff.
Kind regards
I'm not familiar with mediatr, so may be off base here, and it would be much easier to answer this question if we saw what your controller was doing. If you're able, please supply the code, as without that insight, I'm left to guess a little, but I'll try.
If GetChannelGroupChannelById's constructor expects an ID (an int?), FakeItEasy will provide an ID when it makes the Fake version. If it's an int, FakeItEasy will provide a 0, unless you've done some very fancy configuration you've not shown us. If that's supposed to line up with some other value in your code and doesn't, it may cause your problem.
Otherwise, I see you have a Fake IMapper, that is never configured, but is passed into the controller. I'm guessing this is supposed to translate some values. An unconfigured Fake will return a dummy value (or default if no dummy value can be made). It's possible that this unconfigured mapper is interrupting your flow.
(I also see that service in the test class constructor is unused. I would remove it or use it. It may not be part of your problem, but it's at least distracting.)
Related
I'm currently making some UnitTests for some new features I've added to our ASP.NET project (no it's not test-driving design). We use the NHibernate framework and use the UnitTest Mock-ing library FakeItEasy.
I have the following class & method which I want to test:
public class Round
{
public static Round Create(List<Company> activeCompanies, Period period,
BusinessUser user, BusinessUser systemUser,
ISession session, IEntityQuery entityQuery,
RoundProcessBuilder processBuilder)
{
var round = new Round
{
Processes = new List<Process>();
Period = period,
CreationDate = DateTime.Now,
CreatedBy = user
};
// Save the Round in the DB so we can use it's Id in the Processes:
session.Save(round);
foreach (var company in activeCompanies)
{
var companyData = session.Get<CompanyData>(company.Id);
var processResult =
roundProcessBuilder.Build(
systemUser,
new CreateRoundProcessData(company, round, companyData),
entityQuery,
session);
processResult.HandleProcess(process =>
{
// serviceBus can stay null
process.Create(systemUser, DateTime.Now, session, null);
// No need to save the session here. If something went
// wrong we don't want halve of the processes being saved
round.Processes.Add(process);
// It's all or nothing
});
}
return round;
}
}
What I mainly want to test: When I use this Round#Create method with let's say 100 active companies, it should create 100 processes, and each of those processes should contain the RoundId.
This is my UnitTest so far:
[TestFixture]
public class RoundTest
{
private BusinessUser _systemUser;
private DateTime _creationDateRound1;
private List<Company> _activeCompanies;
private RoundProcessBuilder _roundProcessBuilder;
private ISession _session;
[SetUp]
public void Setup()
{
_creationDateRound1 = new DateTime(2015, 10, 5);
_systemUser = TestHelper.CreateBusinessUser(Role.Create("systemuser", "test",
Int32.MaxValue));
_activeCompanies = new List<Company>
{
TestHelper.CreateCompany();
};
_roundProcessBuilder = A.Fake<RoundProcessBuilder>();
_session = A.Fake<ISession>();
}
[Test]
public void TestCreateRoundWithoutPreviousRound()
{
var fakeExpectedRound = Round.Create(_activeCompanies, DateTime.Now.ToPeriod(),
_systemUser, _systemUser, _session, null, _roundProcessBuilder);
var fakeExpectedRoundData = RoundProcessData.Create(TestHelper.CreateCompany(),
fakeExpectedRound, new CompanyData());
var fakeExpectedProcess = new Process(_systemUser, null, "processName", null,
fakeExpectedRoundData, "controllerName", null);
var processSuccessResult = new ProcessSuccessResult(fakeExpectedProcess);
A.CallTo(() => _roundProcessBuilder.Build(null, null, null, null))
.WithAnyArguments()
.Returns(processSuccessResult);
A.CallTo(() => processSuccessResult.HandleProcess(A<Action<Process>>.Ignored))
.Invokes((Action<Process> action) => action(fakeExpectedProcess));
var round = Round.Create(_activeCompanies, _ceationDateRound1.ToPeriod(),
_systemUser, _systemUser, _session, null, _roundProcessBuilder);
Assert.AreEqual(_activeCompanies.Count, round.Processes.Count, "Number of processes");
Assert.AreEqual(round.Period.Quarter, Math.Ceiling(_creationDateRound1.Month / 3.0m), "Quarter");
Assert.AreEqual(round.Period.Year, round.Year, "Year");
// Test if each of the processes knows the RoundId, have the proper state,
// and are assigned to the systemuser
//foreach (var process in round.Processes)
//{
// var roundProcessData = process.ProcessData as RoundProcessData;
// Assert.IsNotNull(roundProcessData, "All processes should have RoundProcessData-objects as their data-object");
// Assert.AreEqual(roundProcessData.Round.Id, round.Id, "RoundId");
// Assert.AreEqual(process.Phase.State, PhaseState.Start, "Process state should be Start");
// Assert.AreEqual(process.AssignedTo, _systemUser, "AssignedTo should be systemuser");
//}
}
... // More tests
}
My problem lies in the following code:
A.CallTo(() => processSuccessResult.HandleProcess(A<Action<Process>>.Ignored))
.Invokes((Action<Process> action) => action(fakeExpectedProcess));
It gives an "The specified object is not recognized as a fake object." error.
The reason I have this part of the code is because the process in the following part was null without it:
processResult.HandleProcess(process => // <- this was null
{
process.Create(systemUser, DateTime.Now, session, null);
round.Processes.Add(process);
});
PS: I uncommented the foreach with additional checks in my UnitTest because it most likely is pretty useless anyway when I mock the process itself.. My main test is if processes are created and added to the list based on the active companies given.
Your problem seems to be that you are trying to add "fake" logic to an object that is not in fact, a fake:
// You create this as an instance of ProcessSuccessResult:
var processSuccessResult = new ProcessSuccessResult(fakeExpectedProcess);
...then proceed to attempt to add a condition to it here:
A.CallTo(() =>
processSuccessResult
.HandleProcess(A<Action<Process>>.Ignored))
.Invokes((Action<Process> action) => action(fakeExpectedProcess));
In order to do this last bit, the variable processSuccessResult will need to be a fake instance of an interface, so that FakeItEasy can work with it, and apply the logic you want.
I'm assuming ProcessSuccessResult is a class you have access to, and are able to edit? If so, you should be able to add an interface to it, that will contain the methods you need, so you can work against that later.
Once you've defined that, you should be able to create your fake object as follows, where IProcessSuccessResult will be a fake implementation of your interface, provided by FakeItEasy:
var processSuccessResult = A.Fake<IProcessSuccessResult>();
Now you should be able to add logic to that fake object using A.CallTo(...).
Of course, this will imply that the real implementation of your class ProcessSuccessResult is not included or called via the variable processSuccessResult. If part of it needs to be, then you might try to either:
Add logic similar to it, or calls to it from the fake object using FakeItEasy's set up code (although this might get overly complicated), OR:
Add a separate variable to contain an instance of the real class (i.e. two variables fakeProcessSuccessResult and processSuccessResult, respectively), and use separate tests for testing separate aspects of your both this class, and it's usages.
I would recommend the latter, if possible.
I hope this is clear enough, and that this will be useful to you. I know it can be quite complicated sometimes, to find the optimal strategy for testing things like this.
I'm trying to test a private method on a mocked object. Please, calm down, I know you're getting your pitchforks out.
I'm well aware everything about to say can be answered by yelling REFACTOR at me. I just need a straight answer. Someone look me in the eyes and tell me this can't be done. It's an ungoogleable problem, so I just need to hear it.
Here's what I'm dealing with.
public class SecretManager
{
protected virtual string AwfulString { get { return "AWFUL, AWFUL THING"; }
public SecretManager()
{
//do something awful that should be done using injection
}
private string RevealSecretMessage()
{
return "don't forget to drink your ovaltine";
}
}
Here's me trying to test it.
var mgr = new Mock<SecretManager>();
mgr.Protected().SetupGet<string>("AwfulThing").Returns("");
var privateObj = new PrivateObject(mgr.Object);
string secretmsg = privateObj.Invoke("RevealSecretMessage");
Assert.IsTrue(secretmsg.Contains("ovaltine"));
and the exception:
System.MissingMethodException: Method 'Castle.Proxies.SecretManagerProxy.RevealSecretMessage' not found
Is what I'm trying to do, mad as it is, possible? Or is this simply too much hubris for a unit test to bear?
You're trying to call a method on the proxy that Castle created. The proxy won't have access to the private method on the class that it inherits from because, well, the method is private. Remember that Castle.Proxies.SecretManagerProxy is actually a subclass of SecretManager.
Do you really need a mock of SecretManager? I realize your code is a slimmed down abstract of the real code, but it seems the only thing you're doing with the mock is setting up a return for a property that isn't used by the method you're trying to test anyway.
var privateObj = new PrivateObject(mgr.Object, new PrivateType(typeof(SecretManager)));
string secretmsg = privateObj.Invoke("RevealSecretMessage");
It will work by specifying PrivateType for the PrivateObject.
Your code should be following for what you are trying to test. You don't need to mock the SecretManager and SetGet "AwfulThing" as you are not using it.
var privateObj = new PrivateObject(new SecretManager());
string secretmsg = (string)privateObj.Invoke("RevealSecretMessage", new object[] { });
Assert.IsTrue(secretmsg.Contains("ovaltine"));
But ideally you shouldn't be testing Private methods. See below article for the explanation:
http://lassekoskela.com/thoughts/24/test-everything-but-not-private-methods/
Coming from using Moq, I'm used to being able to Setup mocks as Verifiable. As you know, this is handy when you want to ensure your code under test actually called a method on a dependency.
e.g. in Moq:
// Set up the Moq mock to be verified
mockDependency.Setup(x => x.SomethingImportantToKnow()).Verifiable("Darn, this did not get called.");
target = new ClassUnderTest(mockDependency);
// Act on the object under test, using the mock dependency
target.DoThingsThatShouldUseTheDependency();
// Verify the mock was called.
mockDependency.Verify();
I've been using VS2012's "Fakes Framework" (for lack of knowing a better name for it), which is quite slick and I'm starting to prefer it to Moq, as it seems a bit more expressive and makes Shims easy. However, I can't figure out how to reproduce behavior similar to Moq's Verifiable/Verify implementation. I found the InstanceObserver property on the Stubs, which sounds like it might be what I want, but there's no documentation as of 9/4/12, and I'm not clear how to use it, if it's even the right thing.
Can anyone point me in the right direction on doing something like Moq Verifiable/Verify with VS2012's Fakes?
-- 9/5/12 Edit --
I realized a solution to the problem, but I'd still like to know if there's a built-in way to do it with VS2012 Fakes. I'll leave this open a little while for someone to claim if they can. Here's the basic idea I have (apologies if it doesn't compile).
[TestClass]
public class ClassUnderTestTests
{
private class Arrangements
{
public ClassUnderTest Target;
public bool SomethingImportantToKnowWasCalled = false; // Create a flag!
public Arrangements()
{
var mockDependency = new Fakes.StubIDependency // Fakes sweetness.
{
SomethingImportantToKnow = () => { SomethingImportantToKnowWasCalled = true; } // Set the flag!
}
Target = new ClassUnderTest(mockDependency);
}
}
[TestMethod]
public void DoThingThatShouldUseTheDependency_Condition_Result()
{
// arrange
var arrangements = new Arrangements();
// act
arrangements.Target.DoThingThatShouldUseTheDependency();
// assert
Assert.IsTrue(arrangements.SomethingImportantToKnowWasCalled); // Voila!
}
}
-- 9/5/12 End edit --
Since I've heard no better solutions, I'm calling the edits from 9/5/12 the best approach for now.
EDIT
Found the magic article that describes best practices. http://www.peterprovost.org/blog/2012/11/29/visual-studio-2012-fakes-part-3/
Although it might make sense in complex scenarios, you don't have to use a separate (Arrangements) class to store information about methods being called. Here is a simpler way of verifying that a method was called with Fakes, which stores the information in a local variable instead of a field of a separate class. Like your example it implies that ClassUnderTest calls a method of the IDependency interface.
[TestMethod]
public void DoThingThatShouldUseTheDependency_Condition_Result()
{
// arrange
bool dependencyCalled = false;
var dependency = new Fakes.StubIDependency()
{
DoStuff = () => dependencyCalled = true;
}
var target = new ClassUnderTest(dependency);
// act
target.DoStuff();
// assert
Assert.IsTrue(dependencyCalled);
}
I'm trying to become more familiar with the Rhinomocks framework, and I'm trying to understand the Expect methods of rhinomocks.
Here's a unit test I have written:
[TestMethod]
public void Create_ValidModelData_CreatesNewEventObjectWithGivenSlugId()
{
//Arrange
var eventList = new List<Event>() { new Event() { Slug = "test-user" } };
_stubbedEventRepository.Stub(x => x.GetEvents())
.Return(eventList);
_stubbedEventRepository
.Expect(x => x.SaveEvent(eventList.SingleOrDefault()))
.Repeat
.Once();
var controller = new EventController(_stubbedEventRepository);
EventViewModel model = new EventViewModel();
//Act
//controller.Create(model); COMMENTED OUT
//Assert
_stubbedEventRepository.VerifyAllExpectations();
}
I thought I understood this code to only pass if the SaveEvent(...) method get's called exactly once. However, with controller.Create(model) commented out, the test still passes. Inside controller.Create(model) is where the SaveEvent() method gets called.
I tried the following:
_stubbedEventRepository
.Expect(x => x.SaveEvent(eventList.SingleOrDefault()));
But it still passes every time, so what am I doing incorrectly stack overflow? The sources I have looked at online haven't been able to help me. Why is VerifyAllExpectations() yielding a successful unit test?
Thank you!
Here's the body of the controller constructor:
public EventController(IEventRepository eventRepository)
{
_eventRepository = eventRepository;
}
edit:
// member variables
private IEventRepository _stubbedEventRepository;
[TestInitialize]
public void SetupTests()
{
_stubbedEventRepository = MockRepository.GenerateStub<IEventRepository>();
}
If you want to verify the behavior of the code under test, you will use a mock with the appropriate expectation, and verify that. If you want just to pass a value that may need to act in a certain way, but isn't the focus of this test, you will use a stub.
I'm still trying to get my head around mocking. Right now, I'm trying to test my Save method on my UserService. As such, I'm mocking out my IRepository which my UserService class uses.
What I don't get is... if i normally save this user to my DB/Repository, it magically gets an Identity, which it then gets set, into my instance object. No rocket science stuff, here.
What I don't understand is, how do i mock this? should I care? I thought I should. Or.. is it that i don't care about that .. because I'm just making sure that the Repository method is called .. not so much that I get the correct data BACK from it.
Here's my pseudo unit test code. (unit test, not integration test .. hence the mock'd repository)...
[TestMethod]
public void GivenANewUserWithValidData_Save_ReturnsTheSameNewUserWithAUserIdDetermined()
{
// Arrange.
var const string passwordSalt = "V4BXAhmHq8IMvR7K20TgoQ=="
var user = new User
{
DisplayName = "Test",
Email = "foo#foo.com",
PasswordSalt = passwordSalt ,
Password = "foobar".ToSha2Hash(passwordSalt)
};
var mockUserRepository = new Mock<IRepository<User>>();
mockUserRepository.Setup(x => x.Save(It.IsAny<User>())).Verifiable();
// Configure this repo in our Dependency Injection.
ObjectFactory.Inject(typeof (IRepository<User>), mockUserRepository.Object);
// Act.
using (new TransactionScope())
{
UserService.Save(user);
UnitOfWork.Commit(); // <-- not sure about this.. currently it's still
// an EntityFramework context.
// I need to change this to.. something??
// Assert.
Assert.IsNotNull(user);
Assert.IsTrue(user.UserId > 0);
}
}
and the user service looks like this..
public class UserService : IUserService
{
public UserService(IRepository<User> userRepository,
ILoggingService loggingService)
{
// .. snip ..
public void Save(User user) { .. }
}
}
Any suggestions?
If you are unit testing UserService.Save(), then all your test should care about is that the repository is called. It's the responsibility of the repository tests to verify that an object is saved correctly.
That's actually something easy to do. You're setting up the Mock object like so:
mockUserRepository.Setup(x => x.Save(user)).Callback(() => user.UserId = 10);
// mocking the value of 10 being insterted into the key
You can even continue using It.IsAny() if you want in the setup, but basically all you need to do is attach the callback to the end of your setup method.
> 1) How should I test a [UserService.]Save method?
Should I care about the result? and
> 2) If i do care about #1 .. then how do i mock the
result also, so I can test that
If the repository is responsible to do the Identity-Magic then it makes no sense to mock this functionality in a test and then verify that this functionality has happened in the test. You want to test the UserService and not the IRepository-mock. The mock is there to crate a fake repository with just enought intelligence that the service does not crash and gets all requirements for the testcase. In this case I do not think that Identity-Magic is required by the service.
If the service is responsible to do the Identity-Magic then it makes sence to test if the id has been set.