假设您具有以下测试方法:
public partial class BaseButtonTemplate : ContentView
{
public static readonly BindableProperty ButtonHeightRequestProperty = BindableProperty.Create(nameof(ButtonHeightRequest), typeof(string), typeof(BaseButtonTemplate), "");
public static readonly BindableProperty EnabledProperty = BindableProperty.Create(nameof(Enabled), typeof(bool), typeof(BaseButtonTemplate), default(bool));
public static readonly BindableProperty FrameBackgroundColorProperty = BindableProperty.Create(nameof(FrameBackgroundColor), typeof(Color), typeof(BaseButtonTemplate), Color.FromHex("FFFFFF"));
public static readonly BindableProperty FrameBorderColorProperty = BindableProperty.Create(nameof(FrameBorderColor), typeof(Color), typeof(BaseButtonTemplate), Color.FromHex("FFFFFF"));
public static readonly BindableProperty LabelTextColorProperty = BindableProperty.Create(nameof(LabelTextColor), typeof(Color), typeof(BaseButtonTemplate), Color.FromHex("FFFFFF"));
public static readonly BindableProperty ParamProperty = BindableProperty.Create(nameof(Param), typeof(string), typeof(BaseButtonTemplate), default(string));
public static readonly BindableProperty TapCommandParamProperty = BindableProperty.Create(nameof(TapCommandParam), typeof(object), typeof(BaseButtonTemplate), default(object));
public static readonly BindableProperty TapCommandProperty = BindableProperty.Create( "TapCommand", typeof(Command), typeof(BaseButtonTemplate), defaultBindingMode: BindingMode.TwoWay, defaultValue: default(Command));
public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(BaseButtonTemplate), default(string));
public Color FrameBackgroundColor { get { return (Color)GetValue(FrameBackgroundColorProperty); } set { SetValue(FrameBackgroundColorProperty, value); } }
public Color FrameBorderColor { get { return (Color)GetValue(FrameBorderColorProperty); } set { SetValue(FrameBorderColorProperty, value); } }
public Color LabelTextColor { get { return (Color)GetValue(LabelTextColorProperty); } set { SetValue(LabelTextColorProperty, value); } }
public Command TapCommand { get { return (Command)GetValue(TapCommandProperty); } set { SetValue(TapCommandProperty, value); } }
public bool Enabled { get; set; }
public object TapCommandParam { get { return (object)GetValue(TapCommandParamProperty); } set { SetValue(TapCommandParamProperty, value); } }
public string ButtonHeightRequest { get { return (string)GetValue(ButtonHeightRequestProperty); } set { SetValue(ButtonHeightRequestProperty, value); } }
public string Param { get { return (string)GetValue(ParamProperty); } set { SetValue(ParamProperty, value); } }
public string Text { get { return (string)GetValue(TextProperty); } set { SetValue(TextProperty, value); } }
}
对这种功能进行单元测试的最佳方法是什么?如果您编写2个测试 断言,当myBool为true时断言repositoryA,而当myBool为false时调用repositoryB,那么对该函数的以下更改仍将使测试通过,但有可能破坏应用程序的功能:
library(tidyverse)
xy <- data.frame(xvar = 1:10, yvar = 1:10)
plotfunc2 <- function(data, x, y){
x <- enquo(x)
y <- enquo(y)
rng <- data %>% summarise(r1 = range(!!x, na.rm = TRUE)[1],
r2 = range(!!x, na.rm = TRUE)[2])
new_data <- data %>% mutate(rescale = (!!x - rng$r1)/(rng$r2 - rng$r1))
ggplot(data, aes(x = !!x, y = !!y)) +
geom_line()
}
plotfunc2(xy, xvar, yvar)
另一方面,如果您断言myBool为true时,则调用repositoryA且未调用repositoryB,这使您更有信心,对函数的任何更改都不会引入错误,但是您可以进行测试取决于实施细节。最好的方法是什么?
如果使用TDD,您会写什么测试才能达到所需的功能?
答案 0 :(得分:0)
回答您的问题(也请阅读我的评论,从更广泛的意义上讲可能是有价值的),我会写类似的东西:(使用Java模拟库JMock)
// with myBool == true
context.checking(new Expectations(){{
oneOf(repositoryA).save(object);
never(repositoryB);
}});
underTest.foo(object, true);
// with myBool == false
context.checking(new Expectations(){{
never(repositoryA);
oneOf(repositoryB).save(object);
}});
underTest.foo(object, false);
答案 1 :(得分:0)
对这种功能进行单元测试的最佳方法是什么?
从重新设计开始吗?
首先开发测试的部分要点是声称可测试的接口也“更好”;更容易食用,更易于维护。
因此,您(正确地)提出的有关测试此方法副作用的观点是一种“设计异味”-暗示此代码设计可能不是用例所需要的。
两种可能性:
一个是代码试图告诉您您有遥测要求;您应该能够查询被测系统,并了解到每个存储库中已经保存了多少个对象,或者最后一个保存到每个存储库中的对象是什么,或者类似的内容。
然后,您可以利用遥测技术编写测试
Given:
telemetry reports that repository B has stored 7 objects
and myBool is true
When:
foo()
Then:
telemetry reports that repository B has stored 7 objects
这基本上将问题分为两部分:一组测试,以确保遥测准确报告存储库保存对象的次数,然后进行foo()
的测试以假定遥测有效。
第二种选择:该测试试图告诉您您希望能够评估程序中正在发生的副作用。因此,请使这些效果成为设计中的头等公民,并编写检查效果的测试。
List<Effect> foo () {
if (myBool) {
return List.of(SaveInRepositoryA);
} else {
return List.of(SaveInRepositoryB);
}
}
现在,您的断言更加容易-您只需确保列表中包含正确数量的元素以及正确的元素即可。
重要说明:这些设计正在做的事情是在您的逻辑和副作用之间形成一个接缝。想象一个边界,在边界的一侧是易于测试的复杂逻辑,因为这是对内存中数据的全部处理;边界的另一端是难以测试的代码,但是它是如此简单直接,显然没有任何错误。