3

ユニットテストにMoqライブラリを使用しています。今私が欲しいのは、オブジェクトに初めてアクセスするとnullが返され、2回目にアクセスすると別のオブジェクトが返されることです。

これが私のコードです

var mock = new Mock<IMyClass>();
mock.Setup(?????);
mock.Setup(?????);

var actual = target.Method(mock.object);

私のメソッドでは、最初にモックオブジェクトがnullかどうかを確認し、nullの場合は初期化してから、いくつかの呼び出しを行います。

bool Method(IMyClass myObj)
{
    if (myObj != null)
        return true;
    else
    {
        myObj = new MyClass();
        bool result = myObj.SomeFunctionReturningBool();
        return result;
    }
}

モックオブジェクトのセットアップを行うには、

また、私はこの行をモックする方法を知る必要があります

bool result = myObj.SomeFunctionReturningBool();
4

5 に答える 5

2

1つのテスト方法で2つのテストを実行しようとしているようですが、テストを2つに分割したほうがよいでしょうか。

また、メソッドにnullが渡された場合は、新しいオブジェクトを初期化する必要があります。これをテストするには、のインスタンスの作成を担当するファクトリオブジェクトを作成することをお勧めしますMyClass。新しいコードは次のようになります。

interface IMyClassFactory
{
    IMyClass CreateMyClass();
}

bool Method(IMyClass myObj, IMyClassFactory myClassFactory)
{
    if (myObj != null)
    {
        return true;
    }

    myObj = myClassFactory.CreateMyClass();
    return myObj.SomeFunctionReturningBool();
}

その場合、テストは次のようになります。

[Test]
public void Method_ShouldReturnTrueIfNotPassedNull()
{
    Assert.That(target.Method(new MyClass()), Is.True);
}

[Test]
public void Method_ShouldCreateObjectAndReturnResultOfSomeFunctionIfPassedNull()
{
    // Arrange
    bool expectedResult = false;

    var mockMyClass = new Mock<IMyClass>();
    mockMyClass.Setup(x => x.SomeFunctionReturningBool()).Returns(expectedResult);

    var mockMyFactory = new Mock<IMyClassFactory>();
    mockMyFactory.Setup(x => x.CreateMyClass()).Returns(mockMyClass.Object);

    // Act
    var result = target.Method(null, mockMyFactory.Object);

    // Assert
    mockMyClass.Verify(x => x.SomeFunctionReturningBool(), Times.Once());
    mockMyFactory.Verify(x => x.CreateMyClass(), Times.Once());
    Assert.That(result, Is.EqualTo(expectedResult));
}

ここでは、ファクトリパターンを使用して、タイプのオブジェクトを作成できるオブジェクトを渡しIMyClass、ファクトリ自体をモックしました。

メソッドのシグネチャを変更したくない場合は、クラスのコンストラクターにファクトリを作成し、クラスのパブリックプロパティを介してアクセスできるようにします。その後、模擬工場によるテストで上書きできます。これは依存性注入と呼ばれます。

于 2012-07-16T10:43:52.570 に答える
1

Moq-nullを返す-この作業例は、Moqを使用してnullを返す方法を示しています。必要なコード行は以下のコメント行ですが、完全に機能する例を以下に示します。

// _mockShopService.Setup(x => x.GetProduct(It.IsAny<string>())).Returns(() => null);

using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

public class Product
{
    public string Id { get; set; }
    public string Name { get; set; }
}

public interface IShopService
{
    Product GetProduct(string productId);
}

public class ShopService : IShopService
{
    public Product GetProduct(string productId)
    {
        if (string.IsNullOrWhiteSpace(productId))
        {
            return new Product();
        }

        return new Product { Id = "8160807887984", Name = "How to return null in Moq" };
    }
}

public class Shop
{
    private static IShopService _shopService;

    public Shop(IShopService shopService)
    {
        _shopService = shopService;
    }

    public Product GetProduct(string productId)
    {
        Product product = _shopService.GetProduct(productId);

        return product;
    }
}

[TestClass]
public class ShopTests
{
    Mock<IShopService> _mockShopService;

    [TestInitialize]
    public void Setup()
    {
        _mockShopService = new Mock<IShopService>();
    }

    [TestMethod]
    public void ShopService_GetProduct_Returns_null()
    {
        //Arrange
        Shop shop = new Shop(_mockShopService.Object);

        //This is how we return null --- all other code above is to bring this line of code home
        _mockShopService.Setup(x => x.GetProduct(It.IsAny<string>())).Returns(() => null);

        //Act
        var actual = shop.GetProduct(It.IsAny<string>());

        //Assert

        Assert.IsNull(actual);
    }
}
于 2017-11-20T14:00:26.607 に答える
0

TestFixtureをパラメーターとともに使用できます。このテストは2回実行され、タイプ値が異なります。

using NUnit.Framework;

namespace Project.Tests
{
    [TestFixture(1)] 
    [TestFixture(2)]
    public class MyTest
    {
        private int _intType;

         public MyTest(int type)
         {
             _intType = type;
         }

        [SetUp]
        public void Setup()
        {
            if (_intType==1)
            {
                //Mock Return false
            }
            else
            {
                //Mock Return Value
            }
        }
    }
}
于 2012-07-16T10:50:58.993 に答える
0

結果値をモックするには、次のようにするだけです。

mock.Setup(foo => foo.SomeFunctionReturningBool()).Returns(true); // or false :)

他の質問については、合格する代わりに単体テストでnullを合格するだけで、単体テストmock.objectもそれをカバーします。したがって、基本的に次の2つの単体テストを作成します。

var actual = target.Method(mock.object);

そしてもう1つは:

var actual = target.Method(null);
于 2012-07-16T10:39:48.213 に答える
0

現在、SUTは実装と緊密に連携していMyClassます。newSUT内でキーワードを使用してインスタンス化されたオブジェクトをモックすることはできません。したがって、SUTを単独でテストすることはできず、テストはもはや単体テストではありません。の実装が変更されると(の代わりにMyClass.SomeFunctionReturningBool返されます)、SUTのテストは失敗します。これは起こらないはずです。したがって、作成をいくつかの依存関係(ファクトリ)に委任し、その依存関係をSUTに注入します。truefalse

[Test]
public void ShouldReturnTrueWhenMyClassIsNotNull()
{
    Mock<IMyClassFactory> factory = new Mock<IMyClassFactory>();
    Mock<IMyClass> myClass = new Mock<IMyClass>();
    var foo = new Foo(factory.Object);
    Assert.True(foo.Method(myClass.Object));
}

[Test]
public void ShouldCreateNewMyClassAndReturnSomeFunctionValue()
{
    bool expected = true;
    Mock<IMyClass> myClass = new Mock<IMyClass>();
    myClass.Setup(mc => mc.SomeFunctionReturningBool()).Returns(expected);
    Mock<IMyClassFactory> factory = new Mock<IMyClassFactory>();
    factory.Setup(f => f.CreateMyClass()).Returns(myClass.Object);

    var foo = new Foo(factory.Object);

    Assert.That(foo.Method(null), Is.EqualTo(expected));
    factory.VerifyAll();
    myClass.VerifyAll();
}

ところで、メソッドパラメータへの新しい値の割り当ては、メソッドに渡した参照には影響しません。

実装:

public class Foo
{
    private IMyClassFactory _factory;

    public Foo(IMyClassFactory factory)
    {
        _factory = factory;
    }

    public bool Method(IMyClass myObj)
    {
        if (myObj != null)
            return true;       

        return _factory.CreateMyClass().SomeFunctionReturningBool();
    }
}
于 2012-07-16T11:48:13.850 に答える