1

そのため、ASP.NET MVC 5 で Autofac Automocking を使用しようとしていますが、何らかの理由で機能しません。

これまでのテストは次のとおりです。

using (var mock = AutoMock.GetLoose())
{
            const string mainUserID = "MainUserID";
            const string otherUserID = "OtherUserID";
            ApplicationUser user = new ApplicationUser()
            {
                Id = mainUserID,
                UserName = "TestUser"
            };

            var dataProvider = mock.Mock<IDataProtectionProvider>();
            dataProvider.DefaultValue = DefaultValue.Mock;

            var userManagerMock = mock.Mock<ApplicationUserManager>();
}

ApplicationUserManager をモックすると、テストが失敗します。エラーは次のとおりです。

Result StackTrace:  
at Autofac.Extras.Moq.AutoMock.Mock[T](Parameter[] parameters)
at AwenterWeb_NUnit.AccountControllerTest.<Deactivate_User>d__0.MoveNext() in C:\Users\Fabis\Documents\Docs\Kvalifikācijas darbs 2015\AwenterWeb\AwenterWeb-NUnit\AccountControllerTest.cs:line 51
at NUnit.Framework.AsyncInvocationRegion.AsyncTaskInvocationRegion.WaitForPendingOperationsToComplete(Object invocationResult)
at NUnit.Core.NUnitAsyncTestMethod.RunTestMethod()
Result Message: System.InvalidCastException : Unable to cast object of type 'AwenterWeb.ApplicationUserManager' to type 'Moq.IMocked`1[AwenterWeb.ApplicationUserManager]'.

ApplicationDbContext を自動モックしようとすると同じことが起こり、非常に単純なコンストラクターがあるため、問題は発生しません。モッキングは初めてです - このシナリオではどうすればよいですか?

編集:また、無関係な質問ですが、ご存知かもしれませんが、テストで以前に作成したリストを使用して DbSet の Moq を作成するときに、次のことを行う必要があることに気付きました。

var dbSetMock = new Mock<IDbSet<DbEntity>>();
            dbSetMock.Setup(m => m.Provider).Returns(data.Provider);
            dbSetMock.Setup(m => m.Expression).Returns(data.Expression);
            dbSetMock.Setup(m => m.ElementType).Returns(data.ElementType);
            dbSetMock.Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());

それは本当に直感的ではないようです。モックにリストを取得するように指示する方法はありますか? 次のようなものです:

dbSetMock.Setup(m => m).Returns(data);

または、これらの 4 行を追加せずに既存のリストから DbSet Moq をすばやく作成する他の方法はありますか?

4

1 に答える 1

1

MoqRegistrationHandler.csの ligne 73 を見ると、インターフェイスのみが Autofac.Extras.Moq を使用してmoqableであることがわかります。

var typedService = service as TypedService; 
if (typedService == null || 
    !typedService.ServiceType.IsInterface || 
    typedService.ServiceType.IsGenericType && typedService.ServiceType.GetGenericTypeDefinition() == typeof(IEnumerable<>) || 
    typedService.ServiceType.IsArray || 
    typeof(IStartable).IsAssignableFrom(typedService.ServiceType)) 
    return Enumerable.Empty<IComponentRegistration>(); 


var rb = RegistrationBuilder.ForDelegate((c, p) => CreateMock(c, typedService)) 
    .As(service) 
    .InstancePerLifetimeScope(); 

コードを変更することはできますが、パラメーターのない依存関係で動作させるのは非常に難しい場合があります。

具体的なクラスの代わりにインターフェイスを使用するように依存関係を変更できますか? それが不可能な場合、および/または意味がない場合は、 を使用しMockRepositoryてパラメータのないコンポーネントを作成し、それをAutoMockクラスに注入できます。

class Program
{
    static void Main(string[] args)
    {
        using (var mock = AutoMock.GetLoose())
        {
            /// configure your non interface component with constructor parameters
            /// if foo need more complex parameters you can get them 
            /// using mock.Mock<T>().Object
            var fooMock = mock.MockRepository.Create<Foo>((String)null);
            fooMock.SetupGet(f => f.Value).Returns("test");

            // insert your instance into the container
            mock.Provide<Foo>(fooMock.Object); 


            var bar = mock.Create<Bar>();
            Console.WriteLine(bar.GetValue());
        }
    }
}

public class Foo
{
    public Foo(String value)
    {
        this._value = value;
    }

    private readonly String _value;

    public virtual String Value
    {
        get
        {
            return this._value;
        }
    }
}

public interface IBar
{
    String GetValue();
}
public class Bar : IBar
{
    public Bar(Foo foo)
    {
        this._foo = foo;
    }

    private readonly Foo _foo;

    public String GetValue()
    {
        return this._foo.Value;
    }
}

これは完璧な解決策ではありませんが、Autofac.Extras.Moq プロジェクトを大幅にリファクタリングしない限り、これ以上簡単な方法はありません。

于 2015-05-19T14:23:25.810 に答える