2017-01-03 27 views
1

在彈簧MVC項目我有索引/網頁內容的測試:對網站的JUnit測試包含一個字符串或(獨家)等字符串

@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"))); 
    } 
} 

這種測試能正常工作至今。但是現在我想測試字符串「登錄」或(不含)「註銷」的出現,即我想測試這兩個字符串中是否有一個(不是零且不是兩個)字符串出現在內容中。我怎樣才能匹配這個或條件?

我試圖

... 
.andExpect(content().string(
     either(containsString("Login")).or(containsString("Logout")))); 
.... 

但是,這並不工作,要麼(如果這兩個字符串出現在頁面不給錯誤)。

+1

我認爲你應該有兩種測試方法:一種預計「登錄」,因爲你沒有登錄,另一種期望「登出」,因爲你沒有登錄。 – davidxxx

+0

@davidxxx:好點。但讓我們假設他們是不同的字符串(不是「登錄/註銷」)。有沒有辦法匹配這個異或,還是我必須寫我自己的匹配器? – user1583209

回答

1

只要string()方法接受Hamcrest匹配,我在這裏看到兩個選項:

  1. 要麼執行XOR樣匹配器自己(你可以使用這個答案作爲參考https://stackoverflow.com/a/29610402/1782379)...
  2. 。 ..或使用複雜的條件,如「任何人而不是兩者」

    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 
    

個人而言,我更喜歡使用第二個選項。

0
@Test 
public void containsOneOfTwoSubStringsExclusive() { 
    assertTrue((mainString.contains(substring1) && !mainString.contains(substring2)) || 
     (!mainString.contains(substring1) && mainString.contains(substring2))) 
} 
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); 
    } 

} 
相關問題