我有一个执行测试用例的 C++ 应用程序。某些测试用例可能会依赖于其他测试用例的输出。
所有测试用例都实现一个基本接口(interface):
/// base class for all test cases
class ITest
{
public:
virtual void Execute() = 0;
};
产生一些可能对其他测试用例有用的对象的测试用例实现这个接口(interface):
/// implemented by test cases that provide data to other test cases
template< class Obj >
class IDependency
{
public:
virtual Obj Get() = 0;
};
需要来自其他测试用例的数据的测试用例实现此接口(interface):
/// implemented by test cases that require data from other test cases
template< class Obj >
class IDependent
{
public:
void SetDependency( IDependency< Obj >* dependency )
{
dependency_ = dependency;
};
protected:
Obj GetDependency() const
{
return dependency_->Get();
};
private:
IDependency< Obj >* dependency_;
};
两个示例测试用例。一个需要一个 const wchar_t 对象;一个产生那个对象:
/// A test case that provides a "const wchar_t*" object to other test cases
class Foo : public ITest,
public IDependency< const wchar_t* >
{
public:
const wchar_t* Get()
{
if( object_.length() == 0 )
Execute();
return object_.c_str();
};
virtual void Execute()
{
printf( "Execute Foo\n" );
object_ = L"Object produced by Foo";
};
private:
std::wstring object_;
};
/// A test case that first requires a "const wchar_t*" object
class Bar : public ITest,
public IDependent< const wchar_t* >
{
public:
virtual void Execute()
{
const wchar_t* needed_object = GetDependency();
printf( "Execute Bar with %S\n", needed_object );
};
};
测试用例存储在列表中。案例通过注册过程添加到列表中:
/// List of test cases to execute
std::vector< ITest* > list_;
/// Register a test case to execute with the system
void Register( ITest* test_case )
{
list_.push_back( test_case );
}
这是我的问题。我想实现也接受依赖项的“Register()”函数的重载。但是,因为依赖项可以是任何类型(不仅仅是本示例中的“const wchar_t*”),所以我不确定如何管理它。下面是我正在寻找的或多或少的示例,但我不确定如何让它工作。
/// Register a test case with dependencies with the system
void Register( ITest* test_case, ITest* dependency, ... )
{
IDependent< ??? >* dependent = dynamic_cast< IDependent< ??? >* >( test_case );
IDependency< ??? >* dep = dynamic_cast< IDependency< ??? >* >( dependency );
va_list dep_list;
for( va_start( dep_list, dependency );
NULL != dep;
dep = dynamic_cast< IDependency< ??? >* >( va_arg( dep_list, ITest* ) ) )
{
dependent->SetDependency( dep );
}
va_end( dep_list );
Register( test_case );
}
用法示例:
int _tmain( int argc, _TCHAR* argv[] )
{
/// Test case Foo
Foo foo;
/// Test case bar (depends on Foo)
Bar bar;
/// Register test case Bar with a dependency on Foo
Register( &bar, &foo );
/// Execute Bar. Because it depends on Foo, that will be executed first
list_->begin()->Execute();
return 0;
}
预期输出:
Execute Foo
Execute Bar with Object produced by Foo
有人对我如何成功实现此架构有任何建议吗? (或者实际有效的更好架构?)
谢谢, 保罗H
最佳答案
我看到了两种可能的解决方案。
使 Register() 方法成为模板。 简单的解决方案是将依赖项的数量限制在某个合理的最大值。
template <class T, class D1>
void Register(T* test_case, IDependency<D1>* d1)
{
BOOST_STATIC_ASSERT(boost::is_base_and_derived<IDependent<D1>, T>::value);
// since we now know that T is a IDependent<D1>, a dynamic_cast would only be necessary
// to allow virtual inheritance.
static_cast<IDependent<D1>*>(test_case)->SetDependency(d1);
Register(test_case);
}
template <class T, class D1, class D2>
void Register(T* test_case, IDependency<D1>* d1, IDependency<D2>* d2)
{
BOOST_STATIC_ASSERT(boost::is_base_and_derived<IDependent<D1>, T>::value);
static_cast<IDependent<D1>*>(test_case)->SetDependency(d1);
Register(test_case, d2);
}
template <class T, class D1, class D2, class D3>
void Register(T* test_case, IDependency<D1>* d1, IDependency<D2>* d2, IDependency<D3>* d3)
{
BOOST_STATIC_ASSERT(boost::is_base_and_derived<IDependent<D1>, T>::value);
static_cast<IDependent<D1>*>(test_case)->SetDependency(d1);
Register(test_case, d2, d3);
}
// ...
对于支持可变参数模板的编译器,这可能只用一个函数模板编写,以获得无限数量的依赖项。
或者你可以让 Register() 返回一个代理类,这样你就可以这样写:
Register(test_case)(dep1)(dep2)(dep3) /* ... */ (depN);
代理类将存储指向容器和测试用例的指针,并定义一个函数调用运算符,它看起来就像上面示例中的 Register(T* test_case, IDependency* d1) 函数,只是没有“test_case”参数和对 Register(test_case) 的最终调用(可以在代理类的 dtor 中执行)。
如果我理解您正在尝试正确执行的操作,则每个“依赖项”只能产生一种类型的结果。 在这种情况下,您可以像这样修改 IDependency 接口(interface):
class IDependencyBase
{
public:
virtual void ApplyTo(ITest* target) = 0;
};
template <class T>
class IDependency : public IDependencyBase
{
public:
virtual void ApplyTo(ITest* target)
{
// cast to reference gives us an std::bad_cast if the types are not compatible,
// which I think is a good thing here
dynamic_cast<IDependancy<T>&>(*target).SetDependancy(this);
}
virtual T Get() = 0;
};
template <class InputIterator>
void Register(ITest* test_case, InputIterator begin, InputIterator end)
{
for (; begin != end; ++begin)
{
IDependancyBase* dep = *begin;
dep->ApplyTo(test_case);
}
Register(test_case);
}
template <class Container>
void Register(ITest* test_case, Container deps)
{
Register(test_case, deps.begin(), deps.end());
}
现在您似乎很想再次实现您的可变参数解决方案,就像这样(从第二个示例继续):
void Register(ITest* test_case, ...)
{
va_list dep_list;
va_start(dep_list, test_case);
while(IDependencyBase* dep = va_arg(dep_list, ITest*))
dep->ApplyTo(test_case);
va_end(dep_list);
Register( test_case );
}
// and use it like
int _tmain( int argc, _TCHAR* argv[] )
{
Foo foo;
Bar bar;
Register(&foo);
Register(&bar, &foo, 0);
list_->begin()->Execute();
return 0;
}
然而,这并不能保证有效。在上面的代码中,一个 Foo* 被存储为一个 varagrs 参数,并作为一个 IDependencyBase* 读回。这不能保证有效,因为 Foo 和 IDependencyBase 都不是 POD(IIRC 它们都必须是 POD 才能保证有效——也许即使那样也不能保证,我必须在标准中查找它) .这不是什么牵强附会的“不受标准保证但可以在任何地方工作”的事情。引入多重和/或虚拟继承,这几乎肯定会失败。
所以使用 C++ 时的一般建议:除非没有其他方法,否则不要使用可变参数函数。而且总有另一种方式。
关于c++ - dynamic_cast<> 将变量参数传递给模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3764912/
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击
我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request
我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R
我使用Nokogiri(Rubygem)css搜索寻找某些在我的html里面。看起来Nokogiri的css搜索不喜欢正则表达式。我想切换到Nokogiri的xpath搜索,因为这似乎支持搜索字符串中的正则表达式。如何在xpath搜索中实现下面提到的(伪)css搜索?require'rubygems'require'nokogiri'value=Nokogiri::HTML.parse(ABBlaCD3"HTML_END#my_blockisgivenmy_bl="1"#my_eqcorrespondstothisregexmy_eq="\/[0-9]+\/"#FIXMEThefoll
我没有找到太多关于如何执行此操作的信息,尽管有很多关于如何使用像这样的redirect_to将参数传递给重定向的建议:action=>'something',:controller=>'something'在我的应用程序中,我在路由文件中有以下内容match'profile'=>'User#show'我的表演Action是这样的defshow@user=User.find(params[:user])@title=@user.first_nameend重定向发生在同一个用户Controller中,就像这样defregister@title="Registration"@user=Use
我正在使用RubyonRails3.0.9,我想生成一个传递一些自定义参数的link_toURL。也就是说,有一个articles_path(www.my_web_site_name.com/articles)我想生成如下内容:link_to'Samplelinktitle',...#HereIshouldimplementthecode#=>'http://www.my_web_site_name.com/articles?param1=value1¶m2=value2&...我如何编写link_to语句“alàRubyonRailsWay”以实现该目的?如果我想通过传递一些
我收到格式为的回复#我需要将其转换为哈希值(针对活跃商家)。目前我正在遍历变量并执行此操作:response.instance_variables.eachdo|r|my_hash.merge!(r.to_s.delete("@").intern=>response.instance_eval(r.to_s.delete("@")))end这有效,它将生成{:first="charlie",:last=>"kelly"},但它似乎有点hacky和不稳定。有更好的方法吗?编辑:我刚刚意识到我可以使用instance_variable_get作为该等式的第二部分,但这仍然是主要问题。