1

I want to assert that a call on my real object (system under test) was called. Here is my test

// Arrange
var contextFactory = A.Fake<IContextFactory>();
var db = A.Fake<IDatabase>();
A.CallTo(() => contextFactory.GetContext()).Returns(db);
var vm = new MainViewModel(contextFactory);

// Act
vm.Loaded();

// Assert
A.CallTo(() => vm.LoadModels(db)).MustHaveHappened();

I'm getting an ArgumentException that says "The specified object is not recognized as a fake object." How do I test that the LoadModels() method in my MainViewModel gets called from the Loaded() method?

EDIT

The reason I'm doing it this way is because the Loaded() method calls a bunch of other methods when the app starts and I don't want to have to setup all the other stuff for each test, I just want to make sure that all the proper methods get called and then test them individually. I'm open to suggestion for a better way of going about this.

Here are the Loaded and LoadModels methods

internal virtual void Loaded()
{
    using (var db = _contextFactory.GetContext())
    {
        LoadModels(db);
        // bunch of other method calls
    }
}

internal virtual void LoadModels(IDatabase db)
{
    Models = new ObservableCollection<Model>(db.Models);
}
reggaeguitar
  • 1,795
  • 1
  • 27
  • 48
  • You don't assert that the system under test was called. You assert that the system under test called certain other expected functions. – BenCr May 13 '14 at 21:45
  • That doesn't answer my question "How do I test that the LoadModels() method in my MainViewModel gets called from the Loaded() method?" – reggaeguitar May 13 '14 at 21:46
  • 1
    It wasn't supposed to answer your question. It was supposed to point out that you're doing the wrong thing. Usually the fact that LoadModels was called isn't really important. What's important is that given certain paramaters and mocked data (arrange), and after the Loaded method is called (act), the value returned from the method or stored in a public property is what it's expected to be (assert). – BenCr May 13 '14 at 21:51
  • I found another question that's pretty similar here http://stackoverflow.com/questions/17929758/use-fakeiteasys-a-callto-on-another-method-in-same-object?rq=1 – reggaeguitar May 13 '14 at 21:52
  • Sweet, you're not on your own in not really understanding what you're doing. Did you read the answer? "I'm still not convinced it's a good idea. I think you'd be better off relying on other observable behaviour" – BenCr May 13 '14 at 21:55
  • If all that method does is call other methods which are individually tested and don't change any external state then why do you need to confirm that functionality? Do you not trust that the can call methods? I don't have the answer to your question anyway. Good luck. – BenCr May 13 '14 at 22:03
  • I guess the conclusion is that I don't really need to test that the methods are called, I got a little crazy with what I was testing, thanks for your comments – reggaeguitar May 13 '14 at 22:06
  • 1
    @reggaeguitar I suggest you test that `contextFactory.GetContext()` and `db.Models` both get called, as that's the intended functionality, not the inner working of the object. In other word the test would be something like `Loaded loads the models from the database`. – Alxandr May 13 '14 at 22:08
  • The problem is that I then have to setup a ton of other fakes for the Loaded method to not throw NREs – reggaeguitar May 13 '14 at 22:09
  • Just because we've got the ability to mock certain objects doesn't mean we've now got the magic ability to test our applications without doing some work setting up test data. It's just the way it is. It's the first A of triple A testing. You're not really testing YOUR system if you mock everything, you're just testing the mocking framework and the programming language. – BenCr May 13 '14 at 22:13
  • I don't mock the MainViewModel, that's my SUT – reggaeguitar May 13 '14 at 22:14
  • "How do I test that the LoadModels() method in my MainViewModel gets called from the Loaded() method?". This is mocking. – BenCr May 14 '14 at 09:01

2 Answers2

1

It looks like you're verifying a method (vm.LoadModels) that isn't part of the fake (db). You can only verify methods on a fake, not methods that happen to take the fake as an argument.

Tim Long
  • 13,508
  • 19
  • 79
  • 147
  • How would I go about testing that the LoadModels method is called from the Loaded method in the MainViewModel class then? Do I need to put the LoadModels method into a new class? – reggaeguitar May 13 '14 at 21:45
  • No, you just have to make `vm` into a fake too. Do `vm = A.Fake()` and you don't even need the other fakes. As long as it's not sealed that is. You might come into problems with the methods not getting called though because they automatically get overloaded, but I don't know enough about your classes to make that call. If it doesn't work, leave a comment, and I'll assist with it. – Alxandr May 13 '14 at 21:55
  • I tried that, when I step into the vm.Loaded() call, it just jumps to the next line and the assertion fails. The Loaded() method calls a bunch of other methods when the app starts and I don't want to have to setup all the other stuff for each test, I just want to make sure that all the proper methods get called and then test them individually. – reggaeguitar May 13 '14 at 21:59
  • @reggaeguitar Take a look at the following extension-method: https://gist.github.com/Alxandr/4ab0475c0e1ec86dbad8 . I use it quite a lot when dealing with FakeItEasy, and even created an issue that this should be easier in the framework, but that's beside the point. It'll auto-setup to call base methods. Though, as the other comments points out, you are probably testing the wrong thing, rather then testing that `vm.LoadModels` is called, you should probably test that `contextFactory.GetContext()` is called as an result of that. – Alxandr May 13 '14 at 22:02
  • Is ```LoadModels``` virtual? – Juan Lopes May 13 '14 at 22:02
  • FakeItEasy automatically rewrites all virtual methods to do nothing and return `default(T)`. This means that if you create a fake `MainViewModel` and calls `LoadModels` on it, it'll just do nothing, and return `null` probably. You can set it up as `strict` to prevent this behaviour, in which case it'll throw instead. – Alxandr May 13 '14 at 22:04
0

I ended up moving the functionality of LoadModels() to another class that implements IStartupDataLoader and then I was able to test it like this

// Arrange    
var sdl = A.Fake<IStartupDataLoader>();
var exp = A.Fake<ObservableCollection<Model>>();
A.CallTo(() => sdl.LoadModels()).Returns(exp);
var sut = new MainViewModel(sdl);

// Act
sut.Loaded();

// Assert
Assert.That(exp == sut.Models);
reggaeguitar
  • 1,795
  • 1
  • 27
  • 48