亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

動態創建任意對象進行單元測試

動態創建任意對象進行單元測試

C#
墨色風雨 2021-11-28 16:43:34
我們的代碼庫充滿了具有大量數字和字符串字段的域對象。在我的單元測試中,我發現自己手動創建了這些不同對象的實例,如下所示:var car1 = new Car();car1.Make = "Make1";car1.Model = "Model1";car1.Year = 1;var car2 = new Car();car2.Make = "Make2";car2.Model = "Model2";car2.Year = 2;等等..只用一個函數調用自動構建任何類型的對象的最干凈的方法是什么?請記住,我不希望使用隨機值生成字段。任意可重復值(如上面的 1 和 2)是我想要的。
查看完整描述

2 回答

?
眼眸繁星

TA貢獻1873條經驗 獲得超9個贊

既然是域對象,為什么不使用工廠呢?

無論您設置什么值,單元測試都應該是有效的。

如果要測試特定值,則應編寫特定測試。

或者可能是您的需求不同?


查看完整回答
反對 回復 2021-11-28
?
BIG陽

TA貢獻1859條經驗 獲得超6個贊

我最終選擇了一種通用方法,該方法使用反射來自動完成問題顯示的手動完成。以這種方式創建的任何字段都可以被覆蓋,并且必須手動設置任何復雜類型。布爾值只是設置為真。我很想聽聽人們對這樣做的想法。當我構建單元測試時,它為我節省了大量的時間和精力。


這是我的測試最終的外觀(簡單示例,沒有我想用特定值覆蓋的復雜類型或字符串/數字字段,盡管這些也被處理):


[Test]

public void TestCreateCars()

{

    // Arrange

    var expectedCars = new List<Car>();

    expectedCars.Add(TestUtils.CreateObject<Car>(1));

    expectedCars.Add(TestUtils.CreateObject<Car>(2));

    expectedCars.Add(TestUtils.CreateObject<Car>(3));


    // using moq but anything could be used

    _carService.Setup(x => x.GetNewCarsInfo()).Returns(cars);


    var carsFactory = new carFactory(_carService);


    // Act

    var cars = carsFactory.CreateCars();


    // Assert

    Assert.AreEqual(3, cars.Count);

    TestUtils.AssertObjectDefaultFields(cars[0], 1);

    TestUtils.AssertObjectDefaultFields(cars[1], 2);

    TestUtils.AssertObjectDefaultFields(cars[2], 3);


    _carService.VerifyAll();

}

創建對象的方法:


// Use this to instantiate objects of types with a large number of int/string fields for testing.  You can override any values after calling this - complex fields won't be set

//  -sets numeric values on that object to its 'id'

//  -sets string values on that object to the name of the field concatenated with the 'id'

public static T CreateObject<T>(int id)

{

    var instance = (T)Activator.CreateInstance(typeof(T));


    // only set properties with a visible setter

    var properties = typeof(T).GetProperties().Where(prop => prop.GetSetMethod() != null);


    foreach (var property in properties)

    {

        var type = property.PropertyType;

        if (IsNumeric(type))

        {

            type = Nullable.GetUnderlyingType(type) ?? type;

            var value = Convert.ChangeType(id, type);


            property.SetValue(instance, value);

        }

        else if (property.PropertyType == typeof(string))

        {

            property.SetValue(instance, property.Name + id);

        }

        else if (property.PropertyType == typeof(bool))

        {

            property.SetValue(instance, true);

        }

    }


    return instance;

}

斷言以這種方式創建的對象的方法具有預期值:


// Use this to assert that an object created by CreateObject<T> has all of the 'default' values:

//  -numeric values equal its 'id'

//  -string values equal the name of the field concatenated with the 'id'

// 

// unsetProperties: property names that we want to assert are their default values

// ignoreProperties: property names that we don't want to assert anything against - we should assert against these outside of this method

public static void AssertObjectDefaultFields<T>(T obj, int id, HashSet<string> unsetProperties = null, HashSet<string> ignoreProperties = null)

{

    // only test properties with a visible setter, otherwise it wouldnt have been set

    var properties = typeof(T).GetProperties().Where(prop => prop.GetSetMethod() != null);

    unsetProperties = unsetProperties ?? new HashSet<String>();

    ignoreProperties = ignoreProperties ?? new HashSet<String>();


    foreach (var property in properties)

    {

        if(!ignoreProperties.Contains(property.Name))

        {

            if (unsetProperties.Contains(property.Name))

            {

                var defaultValue = property.PropertyType.IsValueType ? Activator.CreateInstance(property.PropertyType) : null;

                Assert.AreEqual(defaultValue, property.GetValue(obj));

            }

            else if (IsNumeric(property.PropertyType))

            {

                Assert.AreEqual(id, property.GetValue(obj));

            }

            else if (property.PropertyType == typeof(string))

            {

                Assert.AreEqual(property.Name + id, property.GetValue(obj));

            }

            else if (property.PropertyType == typeof(bool))

            {

                Assert.AreEqual(true, property.GetValue(obj));

            }

        }

    }

}

用于測試字段的類型是否為數字:


private static bool IsNumeric(Type type)

{

    var NumericTypes = new HashSet<Type>

    {

        typeof(int),  typeof(double),  typeof(decimal),

        typeof(long), typeof(short),   typeof(sbyte),

        typeof(byte), typeof(ulong),   typeof(ushort),

        typeof(uint), typeof(float)

    };


    return NumericTypes.Contains(Nullable.GetUnderlyingType(type) ?? type);

}


查看完整回答
反對 回復 2021-11-28
  • 2 回答
  • 0 關注
  • 301 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號