在spring-mvc项目中,我对索引/主页的内容进行了测试:
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class HomePageTest {
@Autowired
private MockMvc mockMvc;
@Test
public void shouldContainStrings() throws Exception {
this.mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(containsString("Hello World")));
}
}
此测试到目前为止工作正常。但是现在我想测试字符串“Login”或(excl)“Logout”的出现,即我想测试这两个字符串中是否只有一个(不是零而不是两个)出现在内容中。我该如何匹配这个或条件?
我试过
...
.andExpect(content().string(
either(containsString("Login")).or(containsString("Logout"))));
....
但这也不起作用(如果页面中出现两个字符串,则不会出错)。
答案 0 :(得分:1)
只要string()
方法接受Hamcrest匹配器,我就会看到两个选项:
...或使用复杂的条件,例如"其中任何一个但不是两个"
Matcher<String> matcher =
allOf(
is(either(containsString("Login")).or(containsString("Logout"))),
is(not(allOf(containsString("Login"), containsString("Logout")))));
assertThat("_Login_", matcher); // OK
assertThat("_Logout_", matcher); // OK
assertThat("_Login_Logout_", matcher); // FAIL
assertThat("__", matcher); // FAIL
我个人更喜欢使用第二种选择。
答案 1 :(得分:0)
@Test
public void containsOneOfTwoSubStringsExclusive() {
assertTrue((mainString.contains(substring1) && !mainString.contains(substring2)) ||
(!mainString.contains(substring1) && mainString.contains(substring2)))
}
答案 2 :(得分:0)
当我找不到合适的匹配器时,我必须自己写自定义匹配器。
import java.util.function.BiConsumer;
import javax.annotation.Nonnull;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.core.CombinableMatcher;
/**
* Similar to the {@link CombinableMatcher.CombinableEitherMatcher} but only passes if <em>only one</em> of the given
* matchers {@link Matcher#matches(Object)}.
*
* @author bugorskia
*/
public class EitherXorMatcher<T> extends BaseMatcher<T>{
//_ **FIELDS** _//
@Nonnull
private final Matcher< ? super T > aMatcher;
@Nonnull
private final Matcher< ? super T > bMatcher;
//_ **INNER CLASS**_//
/**
* This is just for the builder pattern/fluent interface.
*/
public static final class EitherXorMatcherBuilder<T>{
//_ **FIELDS** _//
@Nonnull
private final Matcher<? super T> aMatcher;
//_ **CONSTRUCTOR** _//
private EitherXorMatcherBuilder( @Nonnull final Matcher<? super T> aMatcher ){
this.aMatcher = aMatcher;
}
//_ **API METHODS** _//
@Nonnull
public Matcher<T> xor( @Nonnull final Matcher<? super T> anotherMatcher ){
return new EitherXorMatcher<>( aMatcher, anotherMatcher );
}
}
//_ **CONSTRUCTOR** _//
private EitherXorMatcher( @Nonnull final Matcher< ? super T > aMatcher, @Nonnull final Matcher< ? super T > bMatcher ){
this.aMatcher = aMatcher;
this.bMatcher = bMatcher;
}
@Nonnull
public static <T> EitherXorMatcherBuilder<T> exclusivelyEither( final Matcher<? super T> aMatcher ){
return new EitherXorMatcherBuilder<>( aMatcher );
}
@Nonnull
public static <T> Matcher<? super T> exclusivelyEither( @Nonnull final Matcher<? super T> aMatcher, @Nonnull final Matcher<? super T> bMatcher ){
return new EitherXorMatcher<>( aMatcher, bMatcher );
}
@Nonnull @Deprecated
public static <T> EitherXorMatcherBuilder<T> either( final Matcher<? super T> aMatcher ){
return exclusivelyEither( aMatcher );
}
//_ **API METHODS** _//
@Override
public boolean matches( final Object item ){
final boolean aMatches = aMatcher.matches( item );
final boolean bMatches = bMatcher.matches( item );
return xor( aMatches, bMatches );
}
@Override
public void describeTo( final Description description ){
description.appendText( "Either { " );
aMatcher.describeTo( description );
description.appendText( " } xor { " );
bMatcher.describeTo( description );
description.appendText( " } " );
}
@Override
public void describeMismatch( final Object item, final Description description ){
final boolean aMatches = aMatcher.matches( item );
final boolean bMatches = bMatcher.matches( item );
assert !xor( aMatches, bMatches ): "Should not have gotten called!";
assert aMatches == bMatches: "This is implied, and more of a developer comment than a runtime check.";
final BiConsumer<Matcher<? super T>,Description> describer;
final String startWord, joinWord;
if( aMatches ){
startWord = "Both";
joinWord = "and";
describer = Matcher::describeTo;
}else{
startWord = "Neither";
joinWord = "nor";
describer = ( m, d ) -> m.describeMismatch( item, description );
}
description.appendText( startWord ).appendText( " { " );
describer.accept( aMatcher, description );
description.appendText( " } " ).appendText( joinWord ).appendText( " { " );
describer.accept( bMatcher, description );
description.appendText( " } " ).appendText( " matched instead of exactly one." );
}
//_ **HELPER METHODS** _//
private static boolean xor( final boolean aMatches, final boolean bMatches ){
// xor :: one or the other but not both
return ( aMatches || bMatches ) && ! ( aMatches && bMatches );
}
}