Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot SetInstance different objects implementing same interface #22

Open
aateeque opened this issue Nov 25, 2015 · 8 comments
Open

Cannot SetInstance different objects implementing same interface #22

aateeque opened this issue Nov 25, 2015 · 8 comments

Comments

@aateeque
Copy link

The SetInstance<T>(T instance) method of AutoMoqer is designed to inject specific objects. Given a constructor with parameters of the same IType the last SetInstance call will override any previous objects. This is a major flaw in the framework.
An example
A common case is for a ViewModel depending on two IScheduler's the background and the dispatcher. In your ViewModelTest you'd want to have different schedulers passed in, but this is not possible.

@aateeque
Copy link
Author

Don't know what the solution is here with Unity, perhaps some mechanism of injection by param name...no idea how'd that work. But will take a poke and see

@darrencauthon
Copy link
Owner

Ah, I don't know about a major flaw... I've personally used this to write thousands upon thousands of tests, but have never come across this situation.

If I were to write out the scenario of yours as I think I understand it...

// ViewModel.cs
public class ViewModel
{
    public ViewModel(IScheduler scheduler1, IScheduler scheduler2)
    {
        // ...
    }
}

// ViewModelTests.cs

var scheduler1 = new Scheduler();
var scheduler2 = new Scheduler();

var mocker = new AutoMoqer();
mocker.SetInstance<IScheduler>(scheduler1);
mocker.SetInstance<ISche.... # HEAD EXPLODES, UGH, NO WAY TO DO THIS

I can't think of a way to resolve this within AutoMoq, though. On those rare cases when AutoMoq wouldn't work for me, like in this case... I wouldn't use AutoMoq.

AutoMoq is meant to be a tool to make testing easier. It fits many use cases very well, but some others not so well. I'm totally open to an idea that will fix this edge case, but only under these two stipulations:

  1. It doesn't affect anybody else using the library, and
  2. It "makes sense."

(2) is a little vague, but I can't imagine a solution that will work in this case. I'd love to be shown another way because then I'd learn that better way, because... I don't know what the solution would be.

😄

@darrencauthon
Copy link
Owner

Now that I think about it, I have come across this situation... but I always handled with a different design.

Instead of:

public class ViewModel
{
    public ViewModel(IScheduler scheduler1, IScheduler scheduler2)
    {
        // ...
    }
}

I'd write:

public class ViewModel
{
    public ViewModel(IEnumerable<IScheduler> schedulers)
    {
        // ...
    }
}

The latter can easily be mocked, and is compatible with AutoMoq.

Of course this is only applicable if all of the schedulers are meant to do the same thing. I just can't think of a case where I've ever needed two instances of the same interface, but passed in a way where they'd be received as two separate arguments through the constructor.

@darrencauthon
Copy link
Owner

My first thought is to use a string when registering to distinguish... but that wouldn't be very refactor-friendly.

We could use the order, but again... refactor-friendly. But perhaps not as bad as the arbitrary string.

@aateeque
Copy link
Author

In retrospect major flaw is surely an overstatement. I've used AutoMocking before and enjoy that undoubtedly and find it useful. But in the case of reactive applications you do find two ISchedulers being passed into the ViewModels often.
The IEnumerable<T> option is a solution surely. But not as elegant. Using names of params seems more so. Could we use nameof()?

@darrencauthon
Copy link
Owner

We could use nameof()... when it's available, though... isn't it coming in a later version of C#?

And all of the examples I've seen of it are with things like properties... can it be used with variables?

@aateeque
Copy link
Author

It is available in VS2015, so C#6. It can be used to get the string name of anything, param, T, etc. Just created an example here
So can we move to C# 6?

@darrencauthon
Copy link
Owner

Ah, I'd rather not. But perhaps there is a way to use a string as the identifier, which would leave it to the user to use nameof or not. But how to use that string? hmm...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants