在测试期间,我在定义接口(interface)和替换模拟方面取得了很多成功,但我在模拟 bufio.Scanner 输入时遇到了问题:
file := &mockFile{
ReadFunc: func(p []byte) (int, error) {
reader := bufio.NewReader(bytes.NewReader([]byte(consulPropertiesFile)))
return reader.Read(p)
},
CloseFunc: func() error {
return nil
},
}
fs := &mockFileSystem{
OpenFunc: func(name string) (File, error) {
return file, nil
},
}
properties, err := readConsulPropertiesFile(fs)
虽然这似乎可行,但一旦扫描器到达我的字符串末尾,它似乎就回到了开头,并且读取了太多(这次它似乎读取了不止一行)。这就像我需要在适当的时间在我的 ReadFunc 中手动返回 EOF 错误,但我不确定如何确定何时应该这样做...
扫描器代码(从 here 提取):
f, err := file.Open("/run/secrets/consul-web4.properties")
if err != nil {
return nil, err
}
defer f.Close()
properties := map[string]string{}
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := scanner.Text()
if equal := strings.Index(line, "="); equal >= 0 {
if key := strings.TrimSpace(line[:equal]); len(key) > 0 {
value := ""
if len(line) > equal {
value = strings.TrimSpace(line[equal+1:])
}
properties[key] = value
}
}
}
我还没有重构上面的...
我在我的测试字符串上尝试了以下变体:
const input = `key=value
key=value
key=value
`
const input = "key=value\nkey=value\nkey=value\n"
我已经尝试过 bufio.Reader 和 io.Reader 的实现。
感谢任何帮助/见解!
最佳答案
感谢@Adrian:
我在回家的路上意识到这可能是由于每次调用该方法时都会实例化一个新的阅读器。将读取器实例化从我的 ReadFunc 中移出效果非常好!
感谢@Thundercat 提供的strings.NewReader() 提示,更新代码:
reader := ioutil.NopCloser(strings.NewReader(consulPropertiesFile))
file := &mockFile{
ReadFunc: func(p []byte) (int, error) {
return reader.Read(p)
},
CloseFunc: func() error {
return nil
},
}
对于看到这篇文章并寻找有关如何模拟文件系统等信息的人:
用于打开和统计文件的接口(interface),以及使用 os 包的具体实现:
// FileSystem - interface to the filesystem
type FileSystem interface {
Open(name string) (File, error)
Stat(name string) (os.FileInfo, error)
}
// OsFS - filesystem backed by default os package
type OsFS struct {
}
// Open - open a file
func (o *OsFS) Open(name string) (File, error) {
return os.Open(name)
}
// Stat - get file status
func (o *OsFS) Stat(name string) (os.FileInfo, error) {
return os.Stat(name)
}
上面提到的文件接口(interface):
// File - file interface
type File interface {
io.Closer
io.Reader
io.ReaderAt
io.Seeker
Stat() (os.FileInfo, error)
}
模拟您希望文件系统返回的文件(实现您的代码将使用的方法):
type mockFile struct {
CloseFunc func() error
ReadFunc func(p []byte) (int, error)
ReadAtFunc func(p []byte, off int64) (int, error)
SeekFunc func(offset int64, whence int) (int64, error)
StatFunc func() (os.FileInfo, error)
}
func (m *mockFile) Close() error {
return m.CloseFunc()
}
func (m *mockFile) Read(p []byte) (int, error) {
return m.ReadFunc(p)
}
func (m *mockFile) ReadAt(p []byte, off int64) (int, error) {
return m.ReadAtFunc(p, off)
}
func (m *mockFile) Seek(offset int64, whence int) (int64, error) {
return m.SeekFunc(offset, whence)
}
func (m *mockFile) Stat() (os.FileInfo, error) {
return m.StatFunc()
}
---
reader := ioutil.NopCloser(strings.NewReader("some string, replace with bytes etc"))
file := &mockFile{
ReadFunc: func(p []byte) (int, error) {
return reader.Read(p)
},
CloseFunc: func() error {
return nil
},
}
然后通过 mockFileSystem 返回你的 mockFile:
fs := &mockFileSystem{
OpenFunc: func(name string) (File, error) {
return file, nil
},
}
关于go - 模拟 bufio.Scanner 输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54406712/
是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou
这是针对我无法破坏的现有公共(public)API,但我确实希望对其进行扩展。目前,该方法采用字符串或符号或任何其他在作为第一个参数传递给send时有意义的内容我想添加发送字符串、符号等列表的功能。我可以只使用is_a吗?数组,但还有其他发送列表的方法,这不是很像ruby。我将调用列表中的map,所以第一个倾向是使用respond_to?:map。但是字符串也会响应:map,所以这行不通。 最佳答案 如何将它们全部视为数组?String的行为与仅包含String的Array相同:deffoo(obj,arg)[*arg].eac
假设我在Store的模型中有这个非常简单的方法:defgeocode_addressloc=Store.geocode(address)self.lat=loc.latself.lng=loc.lngend如果我想编写一些不受地理编码服务影响的测试脚本,这些脚本可能已关闭、有限制或取决于我的互联网连接,我该如何模拟地理编码服务?如果我可以将地理编码对象传递到该方法中,那将很容易,但我不知道在这种情况下该怎么做。谢谢!特里斯坦 最佳答案 使用内置模拟和stub的rspecs,你可以做这样的事情:setupdo@subject=MyCl
在ruby中,你可以这样做:classThingpublicdeff1puts"f1"endprivatedeff2puts"f2"endpublicdeff3puts"f3"endprivatedeff4puts"f4"endend现在f1和f3是公共(public)的,f2和f4是私有(private)的。内部发生了什么,允许您调用一个类方法,然后更改方法定义?我怎样才能实现相同的功能(表面上是创建我自己的java之类的注释)例如...classThingfundeff1puts"hey"endnotfundeff2puts"hey"endendfun和notfun将更改以下函数定
我有一个gem,它有一个根据Rails.env的不同行为的方法:defself.envifdefined?(Rails)Rails.envelsif...现在我想编写一个规范来测试这个代码路径。目前我是这样做的:Kernel.const_set(:Rails,nil)Rails.should_receive(:env).and_return('production')...没关系,只是感觉很丑。另一种方法是在spec_helper中声明:moduleRails;end而且效果也很好。但也许有更好的方法?理想情况下,这应该有效:rails=double('Rails')rails.sho
我的ruby脚本从命令行参数获取某些输入。它检查是否缺少任何命令行参数,然后提示用户输入。但是我无法使用gets从用户那里获得输入。示例代码:test.rbname=""ARGV.eachdo|a|ifa.include?('-n')name=aputs"Argument:#{a}"endendifname==""puts"entername:"name=getsputsnameend运行脚本:rubytest.rbraghav-k错误结果:test.rb:6:in`gets':Nosuchfileordirectory-raghav-k(Errno::ENOENT)fromtes
我正在为我的用户实现一些rubyonrails代码推特内容。我正在创建正确的oauth链接...类似http://twitter.com/oauth/authorize?oauth_token=y2RkuftYAEkbEuIF7zKMuzWN30O2XxM8U9j0egtzKv但在我的测试帐户授予对twitter的访问权限后,它会弹出一个页面,上面写着“您已成功授予对.我不知道用户应该在哪里输入此PIN以及他们为什么必须这样做。我认为这不是必要的步骤。Twitter应该将用户重定向到我在应用程序设置中提供的回调URL。有谁知道为什么会这样?更新我找到了thisarticle声明我需
我有一个rspec模拟对象,一个值赋给了属性。我正在努力在我的rspec测试中满足这种期望。只是想知道语法是什么?代码:defcreate@new_campaign=AdCampaign.new(params[:new_campaign])@new_campaign.creationDate="#{Time.now.year}/#{Time.now.mon}/#{Time.now.day}"if@new_campaign.saveflash[:status]="Success"elseflash[:status]="Failed"endend测试it"shouldabletocreat
我正在尝试测试命令行工具的输出。如何使用rspec来“伪造”命令行调用?执行以下操作不起作用:it"shouldcallthecommandlineandreturn'text'"do@p=Pig.new@p.should_receive(:run).with('my_command_line_tool_call').and_return('resulttext')end如何创建stub? 最佳答案 使用newmessageexpectationsyntax:规范/虚拟规范.rbrequire"dummy"describeDummy
在Railcasts上,我注意到一个非常有趣的功能“转到符号”窗口。它像Command-T一样工作,但显示当前文件中可用的类和方法。如何在vim中获取它? 最佳答案 尝试:helptags有各种程序和脚本可以生成标记文件。此外,标记文件格式非常简单,因此很容易将sed(1)或类似的脚本组合在一起,无论您使用何种语言,它们都可以生成标记文件。轻松获取标记文件(除了下载生成器之外)的关键在于格式化样式而不是实际解析语法。 关于ruby-on-rails-Textmate'Gotosymbol