Unit testing 如何为单元测试模拟标准包函数
我有三个职能:Unit testing 如何为单元测试模拟标准包函数,unit-testing,go,Unit Testing,Go,我有三个职能: func IsSymlinks(path string) { ... ... } func (c *MyClass) myFunc1(path string) { ...more code ...more code if IsSymlinks(path) { realPath := filepath.EvalSymlinks(path) } ...more code ...more code } func myFunc2(path
func IsSymlinks(path string) {
...
...
}
func (c *MyClass) myFunc1(path string) {
...more code
...more code
if IsSymlinks(path) {
realPath := filepath.EvalSymlinks(path)
}
...more code
...more code
}
func myFunc2(path string) {
...more code
...more code
if IsSymlinks(path) {
realPath := filepath.EvalSymlinks(path)
}
...more code
...more code
}
type MyEvalLink interface {
IsSymlinks(path string) bool
EvalSymlinks(path string) (string, error)
}
如何通过模拟filepath.EvalSymlinks和IsSymlinks来测试myFunc1和myFunc2?我搜索了一些帖子,发现了一些解决方案
您可以通过使用一个接口来实现这一点。例如,假设您有一个名为Linker的接口:
type Linker interface {
IsSymlinks(path String)
}
现在,您可以将链接器对象嵌入调用IsSymlinks
方法的函数中
type MyClass struct {
Linker
}
func (p *MyClass) myFunc(path String) {
_ = p.Linker.IsSymlinks(path)
}
现在在测试中,您可以创建一个模拟链接器
type mockLinker struct{}
//implement the IsSymlinks on the mockLinker as you wish
p := &MyClass{
Linker: mockLinker,
}
p.myFunc(path)
当p.myFunc
到达IsSymlinks
方法时,它将调用模拟的IsSymlinks
方法
type MyClass struct {
Linker
}
func (p *MyClass) myFunc(path String) {
_ = p.Linker.IsSymlinks(path)
}
对于filepath.EvalSymlinks(path)
您可以将该方法包装到您的另一个方法中,并将新方法添加到同一接口中,模拟该方法,而不是模拟EvalSymlinks
仅为测试目的创建接口可能并不总是最好的主意,因为在某些情况下,可能会导致使用大型接口,而这些接口在Go中不是惯用的,因为这会降低代码的可读性 我认为您可以尝试以不同的方式设计MyClass结构和相关函数。我的意思是从filepath之类的包中获得独立的MyClass对象。首先,创建一个具有两个功能的新接口:
func IsSymlinks(path string) {
...
...
}
func (c *MyClass) myFunc1(path string) {
...more code
...more code
if IsSymlinks(path) {
realPath := filepath.EvalSymlinks(path)
}
...more code
...more code
}
func myFunc2(path string) {
...more code
...more code
if IsSymlinks(path) {
realPath := filepath.EvalSymlinks(path)
}
...more code
...more code
}
type MyEvalLink interface {
IsSymlinks(path string) bool
EvalSymlinks(path string) (string, error)
}
然后,您可以在使用filepath包或伪代码的结构中实现这两个函数:
type EvalLinkUse struct{}
func (p *EvalLinkUse) IsSymlinks(path string) bool {
// put here your real code or fake
}
func (p *EvalLinkUse) EvalSymlinks(path string) (string, error) {
// put here your real code or fake
}
因此,您的代码将更改如下:
type MyClass struct {
...your code
MyEvalLink MyEvalLink
}
func (c *MyClass) myFunc1(path string) {
...more code
...more code
if c.MyEvalLink.IsSymlinks(path) {
realPath := c.MyEvalLink.EvalSymlinks(path)
}
...more code
...more code
}
这适合您的情况吗?非常感谢您的解决方案!我完全同意你的最后一段。我在另一篇文章中看到了类似的想法,我犹豫是否使用它,因为说服自己在MyClass中添加另一个字段只是为了测试两个小函数有点困难。我想看看是否还有其他解决办法。如果没有,我将采用这种接口方法。再次感谢你!由于我更新了我的问题,上述答案可能不容易适用于我的案例。我认为没有任何方法可以测试新的
IsSymlinks
函数,因为它不再是一种方法。我能想到的唯一方法是,如果IsSymlinks
中的核心功能是全局对象上可以模拟的方法。接口通常应在对象可能发生变化但行为相同的情况下使用。如果是这种情况,那么接口就是正确的方法。您的选项#4可以使用,只要测试不会变得不稳定,例如,在测试运行之前尚未创建符号链接,或者在测试运行之后未正确删除符号链接。谢谢!我知道它适用于myFun1,但我不确定如何使用它来测试myFunc2,因为它不是任何类的一部分。谢谢!在操场上,我的理解是为了用MyClass中的Evalinkuse测试myFunc3,在测试中,我需要创建另一个函数(myFunc2),用MockEvalinkuse替换Evalinkuse。如果我的理解是正确的,我不希望重复代码(myFunc2)。此外,MyClass是一个大型结构,我不确定只使用其中两个函数创建它是否是一个好的实践(很抱歉,我是新手)。我同意你的观点,DRY(不要重复你自己)是一个很好的经验法则。去支持组合而不是继承,我用了很长时间,也许其他人可以建议一个更好的解决方案。