使用Xunit测试WPF视图模型

fcy6dtqo  于 2022-11-18  发布在  其他
关注(0)|答案(1)|浏览(148)

最近我被安排到一个新的团队工作,负责人告诉我为他们写的代码写单元测试。我真的不知道从哪里开始。这个应用程序是用C#写的WPF。我对WPF和C#都是新手。他们提到使用Xunit。
这是这个类的前两个函数。我必须对保护函数和公共函数进行单元测试,
类类型为public class DataTableModel<T> : ViewModelBase

public DataTableModel()
        {
            //Setup Drag and Drop Commands:
            RecordReceivedCommand = new DataTableReceivedCommand<T>(this);
            RecordRemovedCommand = new DataTableRemovedCommand<T>(this);
            RecordInsertedCommand = new DataTableInsertedCommand<T>(this);
            View = CollectionViewSource.GetDefaultView(Records);
            
        }
        
        /// <summary>
        /// This method sets up the properties for the table. By default, the first DisplayOption is selected, no search criteria is applies, and only 10 records should be returned.
        /// </summary>
        /// <param name="displayOption">The selected display option</param>
        protected void InstantiateTable(int displayOption = 0)
        {
            _displayOption = displayOption;
            _searchCriteria = "";
            _displayAmount = "10";
            _currentPage = 1;
            _userMessage = "Retrieving data...";
            
            TriggerUpdate();
        }

这些函数是从上面调用的,所以我想我应该包括它们。

/// <summary>
        /// This method is responsible for handling the updates to the recordset that the DataGrid will display.
        /// Upon changes to the search criteria, display amount, display option and the current page, this method will be triggered
        /// </summary>
        /// <param name="resetPage">Inidicates whether the grid should return to page 1.</param>
        protected void TriggerUpdate(bool resetPage = false)
        {

            _currentPage = resetPage ? 1 : _currentPage; //only reset to the first page if indicated
            UserMessage = "Retrieving data...";

            //Retrieve the records if the delegate has been set
            GetRecords?.Invoke();
            UserMessage = Records.Count == 0 ? "No data found" : "";

            Message_ZIndex = !String.IsNullOrWhiteSpace(UserMessage) ? 1 : -1;

            //update the page navigations button's settings when the pages are reset
            UpdatePagination();

        }
 /// <summary>
        /// Update the ability to navigate through the datatable's pages. 
        /// Upon changes the the search criteria, display amount, display option, the number of pages and the current page, this method will be
        /// triggered
        /// </summary>
        private void UpdatePagination()
        {
            if (Pages > 1)
            {
                if (_currentPage == 1)
                {
                    GoToFirstPage = false;
                    GoToPrevPage = false;
                    GoToNextPage = true;
                    GoToLastPage = true;

                }
                else if (_currentPage == Pages)
                {
                    GoToFirstPage = true;
                    GoToPrevPage = true;
                    GoToNextPage = false;
                    GoToLastPage = false;

                }
                else
                {
                    GoToFirstPage = true;
                    GoToPrevPage = true;
                    GoToNextPage = true;
                    GoToLastPage = true;

                }
            }
            else
            {
                GoToFirstPage = false;
                GoToPrevPage = false;
                GoToNextPage = false;
                GoToLastPage = false;

            }
        }

        /// <summary>
        /// Get's the information for the datatable's columns
        /// (NOTE: This method is currently only called via ".Invoke" within the DataTable control.)
        /// </summary>
        /// <returns>A List of the DataTableDisplay attributes for the columns in the table</returns>
        public List<DataTableDisplay> GetTableColumnInformation()
        {

            List<DataTableDisplay> attributes = new List<DataTableDisplay>();
            PropertyInfo[] properties = typeof(T).GetProperties();
            foreach(PropertyInfo property in properties)
            {
                DataTableDisplay attr = property.GetCustomAttribute<DataTableDisplay>(false);
                if (attr != null && !String.IsNullOrWhiteSpace(attr.ColumnTitle))
                {
                    attributes.Add(attr);
                }
            }

            return attributes;

            
        }

首先我想测试构造函数,但后来我不知道如何检查命令变量,所以我转移到InstantiateTable函数。这是我得到的。仍然必须创建对象,所以使用构造函数,但当我试图调用x.InstantiateTable()时,我注意到它是受保护的,所以我不能这样做。
用于创建DataTableModel对象的测试用例。它具有动态类型,因此我将其设为int。

[Fact]
        public void DataTableModel_Created()
        {
            DataTableModel<int> x = new DataTableModel<int>();
            Assert.Equal(0, x.DisplayOption);
            Assert.Equal("", x.SearchCriteria);
            Assert.Equal("10", x.DisplayAmount);
            Assert.Equal(1, x.CurrentPage);
            Assert.Equal("Retrieving data...", x.UserMessage);
            
        }

另一个受保护的功能,我必须进行单元测试。

protected List<T> UpdateTable(List<T> data)
        {
            
            _totalCount = data.Count;
            int recordLimit = String.IsNullOrEmpty(DisplayAmount) ? 0 : Convert.ToInt32(DisplayAmount);
            int startingRecord = recordLimit == 0 ? 0 : (_currentPage == 1 ? 1 : 1 + (recordLimit * (_currentPage - 1)));
            int recordsToSkip = (CurrentPage - 1) * recordLimit;
            int endingRecord = recordLimit == 0 ? 0 : recordLimit > _totalCount ? _totalCount : startingRecord + recordLimit - 1;
            Pages = recordLimit == 0 ? 0 : _totalCount <= recordLimit ? 1 : _totalCount % recordLimit > 0 ? (_totalCount / recordLimit) + 1 : _totalCount / recordLimit;
            List<T> displayRecords = data.Skip(recordsToSkip).Take(recordLimit).ToList();
            DisplayMessage = endingRecord <= _totalCount ? $"Showing {(displayRecords.Count == 0 ? 0 : startingRecord)} to {endingRecord} of {_totalCount} entries" : $"Showing {startingRecord} to {_totalCount} of {_totalCount} entries";
            return displayRecords;
           
        }

还有一个委托函数?我应该测试

public delegate List<T> Filter(List<T> data);

我不知道如何处理。我在大学做的几个单元测试是基本对象,没有调用其他对象。我读过关于模拟和存根对象的文章,我认为模拟数据库来填充表可能是好的。

ars1skjm

ars1skjm1#

不要对函数进行单元测试。对视图模型进行单元测试。
视图模型公开由XAML绑定到GUI控件的属性和命令,以便用户可以与它们交互。
所有这些属性和命令都已经是public,否则它们在XAML中是不可见的,因此您的测试也可以访问它们。
大多数C#程序员在将privateprotected转换为public,或者转换为internal然后使用InternalsVisibleTo之前不会三思而后行,但在我看来,这都是错误的。因此,我们必须进行黑箱测试,而不是白箱测试。
在WPF中测试视图模型时,这意味着您应该只测试向XAML公开的内容。
因此,您的测试应该为视图模型属性设置值,就好像这些值是由GUI控件设置的一样,调用视图模型命令就好像这些命令是由GUI按钮触发的一样。
然后,您的测试应该只检查视图模型属性的值是如何变化的,这就是用户在屏幕上看到的。

相关问题