1

I use xUnit and Moq.

In my MainViewModel class I have a method that is called by two commands. The method updates several properties: `

public void CommandCompletedControlsSetup()
{
    //TokenSource.Dispose();
    UpdateStatusBar = 0;
    VisibilityStatusBar = Visibility.Hidden;
    ValidateButtons();
    ProgressDisplay = "";
    WorkStatus = "";
    VisibilityCancellingMsg = Visibility.Visible;
    VisibilityCancelTestingBtn = Visibility.Collapsed;
    VisibilityTestingBtn = Visibility.Visible;
    VisibilityCancelUpdatingBtn = Visibility.Collapsed;
    VisibilityUpdatingBtn = Visibility.Visible;
}

And I just wanted to avoid testing update of the whole method for each command. First command execution:

public void OnUpdateCancellationExecute(object obj)
{
    _updateDataService.CancelUpdates();

    CommandCompletedControlsSetup(); // here is method call
}

Second command execution:

public void OnSimulateCancellationExecute(object obj)
{
    _simulateDataService.CancelSimulation();

    CommandCompletedControlsSetup(); // here is method call
}

So instead of doing this twice:

[Fact]
public void OnSimulateCancellationExecute_UpdatesViewProps_True()
{
    _viewModel.UpdateStatusBar = 1000;
    _viewModel.VisibilityStatusBar = Visibility.Visible;
    _viewModel.ProgressDisplay = "1000/1000";
    _viewModel.WorkStatus = "some status";
    _viewModel.VisibilityCancellingMsg = Visibility.Hidden;
    _viewModel.VisibilityCancelTestingBtn = Visibility.Visible;
    _viewModel.VisibilityTestingBtn = Visibility.Hidden;
    _viewModel.VisibilityCancelUpdatingBtn = Visibility.Visible;
    _viewModel.VisibilityUpdatingBtn = Visibility.Hidden;

    _viewModel.SimulateCancellationCommand.Execute(null);

    Assert.Equal(0, _viewModel.UpdateStatusBar);
    Assert.Equal(Visibility.Hidden, _viewModel.VisibilityStatusBar);
    Assert.Equal("", _viewModel.ProgressDisplay);
    Assert.Equal("", _viewModel.WorkStatus);
    Assert.Equal(Visibility.Visible, _viewModel.VisibilityCancellingMsg);
    Assert.Equal(Visibility.Collapsed, _viewModel.VisibilityCancelTestingBtn);
    Assert.Equal(Visibility.Visible, _viewModel.VisibilityTestingBtn);
    Assert.Equal(Visibility.Collapsed, _viewModel.VisibilityCancelUpdatingBtn);
    Assert.Equal(Visibility.Visible, _viewModel.VisibilityUpdatingBtn);
}

I wanted to do something like this:

[Fact]
        public void CancellationExecuteMethods_UpdatesViewProps_True()
        {
            _viewModel.SimulateCancellationCommand.Execute(null);

            _viewModel.UpdateCancellationCommand.Execute(null);

            //MainViewModel does not contain definition for Verify - exception
            _viewModel.Verify(sd => sd.CancelUpdates(), Times.Exactly(2));
        }

BUT the MainViewModel is not mocked and I am not sure that I am able to mock it? If yes, then how? If not, is there any alternative to test that VM method was called? Or should I just leave it as something obvious and just test the method by itself?

Johnny
  • 8,939
  • 2
  • 28
  • 33
bakunet
  • 197
  • 1
  • 12
  • Phrases like "should I?" in your title tend to make the question appear "primarily opinion-based" and lead to downvotes and/or closure votes. The question fundamentally seems to be about "how to", so I've removed the relatively unimportant phrase from your title. – Peter Duniho Jul 06 '19 at 05:31
  • @PeterDuniho thank you for understanding. Just because of lack of experience with unit testing I was not sure that is there a sence to test a method call happening or just a called method by itself...? – bakunet Jul 06 '19 at 05:35
  • I understand that part of the question. But that part is opinion-based, and isn't likely to elicit the most useful responses. I would keep your focus on the main part of the question, with respect to how to work with Moq and xUnit to implement the test the way you hope to. – Peter Duniho Jul 06 '19 at 06:07
  • You did not get the point of VM and Unit Testing. A VM is an abstraction of the View and has **only** public properties. A Unit Test will never test the implementation, such as if the method x of the tested instance is getting called. You test if the instance has the right state or has interacted with some external dependencies the way it should. – Sir Rufo Jul 06 '19 at 06:37
  • 1
    The property VisibilityTestingBtn is a good indicator for me: A button on a view should bind to an ICommand property of the VM. Now everything is clear what should happen if you press the button and when the button is enabled or not. And when the ICommand property is null the button is hidden. That is abstraction. – Sir Rufo Jul 06 '19 at 06:41
  • @SirRufo as I understand, testing single property change, for ex. `VisibilityTestingBtn`, should be enough to cover the test, if I want to be sure that `ICommand` enables several props? Please correct me if I am wrong. – bakunet Jul 06 '19 at 06:55
  • 1
    No, the VM should never have a property of type System.Windows.Visibility - instead use the TestingCommand property itself - f.i. if it is null, then do not show the button. Or use some boolean state of the VM with a converter in the view to control visibility – Sir Rufo Jul 06 '19 at 08:25

1 Answers1

1

Mocking and Dependency Inversion Principle go hand in hand. If you want to mock something you need to 'invert the dependency' of the mocking target, so that you can replace a concrete implementation wit an actual mocked object instance. In your concrete example you would need to extract CommandCompletedControlsSetup() into a separate class and pass it to the view model using constructor injection. Since the view model needs a parameterless constructor in order to instantiate it in XAML, this would lead to significant changes to the application start-up. I don't know how you are doing it right now, but you would need to bootstrap your application and let your DI container create the view instances and show the manually.

Another option you have is to leave this commands alone and don't test them explicitly. Your commands are composed of a set of methods. One method to be precise (the other method is CommandCompletedControlsSetup() and this you don't want to test).
In both of your examples your commands invoke a public method of a service class:
updateDataService.CancelUpdates(); and _simulateDataService.CancelSimulation();.
So, you probably already tested this services. If not the you could or should test them. If you tested this services, you also implicitly tested your view model commands, since they depend on those services. This way you stepped around CommandCompletedControlsSetup().

But in general, every behaviour you would like to mock and that is part of the type you want to test, must be injected into that type.

As a side note, I personally prefer to bind my control's visibility to a boolean property exposed by my view models using a converter. You can use the BooleanToVisibilityConverter converter provided by the .NET framework. This way I avoid references to view related assemblies.

BionicCode
  • 1
  • 4
  • 28
  • 44
  • Thank you for comment that, as I belive, closes the topic. And I agree, same like **Sir Rufo** wrote, it is better to use converter for visibility props. Methods in service classes are tested. I think now to avoid creating new dependency for tested method and just to test VM method by itself. I belive, that it will fit reasonable practice. – bakunet Jul 06 '19 at 14:35
  • **UPDATE** BooleanToVisibilityConverter did the job, didnt have to use any converter. Also here are alternative ways to play with Visibility prop: https://stackoverflow.com/questions/7000819/binding-a-buttons-visibility-to-a-bool-value-in-viewmodel – bakunet Jul 06 '19 at 15:19